From 64c1772f5b2cd4adf1eccf843e3a50c5620a2fca Mon Sep 17 00:00:00 2001 From: geethkokila Date: Thu, 24 Mar 2016 11:45:41 +0530 Subject: [PATCH 01/10] Changing the plugins snapshit versions to 2.1.0 from 2.0.4 --- .../org.wso2.carbon.device.mgt.mobile.impl/pom.xml | 4 ++-- .../org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml | 6 +++--- components/device-mgt/pom.xml | 4 ++-- .../org.wso2.carbon.device.mgt.mobile.feature/pom.xml | 4 ++-- features/device-mgt/pom.xml | 4 ++-- pom.xml | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml index 773aaa369..c91d9b7df 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml @@ -22,14 +22,14 @@ device-mgt org.wso2.carbon.devicemgt-plugins - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml 4.0.0 org.wso2.carbon.devicemgt-plugins org.wso2.carbon.device.mgt.mobile.impl - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT bundle WSO2 Carbon - Mobile Device Management Impl WSO2 Carbon - Mobile Device Management Impl diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml index ca385eba4..e19a3f965 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml @@ -3,14 +3,14 @@ device-mgt org.wso2.carbon.devicemgt-plugins - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml 4.0.0 org.wso2.carbon.devicemgt-plugins org.wso2.carbon.device.mgt.mobile.url.printer - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT bundle WSO2 Carbon - Startup Handler That Prints MDM End-User Web-App URL WSO2 Carbon - Startup Handler That Prints MDM End-User Web-App URL @@ -79,4 +79,4 @@ - \ No newline at end of file + diff --git a/components/device-mgt/pom.xml b/components/device-mgt/pom.xml index b4598e644..78a844e8d 100644 --- a/components/device-mgt/pom.xml +++ b/components/device-mgt/pom.xml @@ -22,14 +22,14 @@ org.wso2.carbon.devicemgt-plugins carbon-device-mgt-plugins-parent - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT ../../pom.xml 4.0.0 org.wso2.carbon.devicemgt-plugins device-mgt - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT pom WSO2 Carbon - Mobile Device Management Component http://wso2.org diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml b/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml index a6976fdd9..6e07d9f97 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml +++ b/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml @@ -22,14 +22,14 @@ org.wso2.carbon.devicemgt-plugins device-mgt-feature - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT ../pom.xml 4.0.0 org.wso2.carbon.device.mgt.mobile.feature pom - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT WSO2 Carbon - Mobile Device Management Feature http://wso2.org This feature contains the core bundles required for Mobile Device Management functionality diff --git a/features/device-mgt/pom.xml b/features/device-mgt/pom.xml index b201a53d7..bebd11623 100644 --- a/features/device-mgt/pom.xml +++ b/features/device-mgt/pom.xml @@ -22,14 +22,14 @@ org.wso2.carbon.devicemgt-plugins carbon-device-mgt-plugins-parent - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT ../../pom.xml 4.0.0 org.wso2.carbon.devicemgt-plugins device-mgt-feature - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT pom WSO2 Carbon - Device Management Feature http://wso2.org diff --git a/pom.xml b/pom.xml index 88a21c765..f1e904679 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.wso2.carbon.devicemgt-plugins carbon-device-mgt-plugins-parent pom - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT WSO2 Carbon - Device Management Plugins Parent http://wso2.org WSO2 Carbon - Device Management Plugins Parent @@ -588,11 +588,11 @@ 4.5.8 - 1.0.4-SNAPSHOT + 1.1.0-SNAPSHOT [0.8.0, 2.0.0) - 2.0.4-SNAPSHOT + 2.1.0-SNAPSHOT 1.51.0.0 From c0a25f08bd41be00cfec6b121ad222b987b93a94 Mon Sep 17 00:00:00 2001 From: gayank Date: Thu, 24 Mar 2016 15:31:21 +0530 Subject: [PATCH 02/10] Fixing EMM-1289 --- .../mgt/mobile/impl/android/AndroidFeatureManager.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java index 6b29e8486..e358f19e6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java @@ -240,6 +240,16 @@ public class AndroidFeatureManager implements FeatureManager { feature.setName("Message"); feature.setDescription("Send message"); supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_REBOOT"); + feature.setName("Reboot"); + feature.setDescription("Reboot the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("UPGRADE_FIRMWARE"); + feature.setName("Upgrade Firmware"); + feature.setDescription("Upgrade Firmware"); + supportedFeatures.add(feature); return supportedFeatures; } } \ No newline at end of file From 39d2ce12dc1eba6893ad42b3dd307435bb73144c Mon Sep 17 00:00:00 2001 From: prabathabey Date: Sun, 27 Mar 2016 03:02:20 +0530 Subject: [PATCH 03/10] merging resturctured iot and mobile plugins --- .../build.xml | 78 + .../pom.xml | 90 + .../src/assembly/src.xml | 36 + .../EventReceiver_accelerometer.xml | 26 + .../artifact.xml | 22 + .../artifact.xml | 22 + .../org_wso2_iot_devices_accelerometer.xml | 62 + .../artifact.xml | 23 + ....wso2.iot.devices.accelerometer_1.0.0.json | 20 + .../Accelerometer_Sensor_Script.xml | 31 + .../Sparkscripts_1.0.0/artifact.xml | 23 + .../carbonapps/Accelerometer/artifacts.xml | 29 + .../EventReceiver_battery.xml | 26 + .../Eventreceiver_battery_1.0.0/artifact.xml | 22 + .../Eventstore_battery_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_battery.xml | 62 + .../Eventstream_battery_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.battery_1.0.0.json | 20 + .../Battery_Sensor_Script.xml | 31 + .../Battery/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Battery/artifacts.xml | 29 + .../EventReceiver_gps.xml | 26 + .../GPS/Eventreceiver_gps_1.0.0/artifact.xml | 22 + .../GPS/Eventstore_gps_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_gps.xml | 69 + .../GPS/Eventstream_gps_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.gps_1.0.0.json | 23 + .../Sparkscripts_1.0.0/GPS_Sensor_Script.xml | 31 + .../GPS/Sparkscripts_1.0.0/artifact.xml | 22 + .../resources/carbonapps/GPS/artifacts.xml | 29 + .../EventReceiver_gravity.xml | 26 + .../Eventreceiver_gravaity_1.0.0/artifact.xml | 22 + .../Eventstore_gravity_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_gravity.xml | 62 + .../Eventstream_gravity_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.gravity_1.0.0.json | 20 + .../Gravity_Sensor_Script.xml | 31 + .../Gravity/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Gravity/artifacts.xml | 29 + .../EventReceiver_gyroscope.xml | 26 + .../artifact.xml | 22 + .../Eventstore_gyroscope_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_gyroscope.xml | 62 + .../Eventstream_gyroscope_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.gyroscope_1.0.0.json | 20 + .../Gyroscope_Sensor_Script.xml | 31 + .../Gyroscope/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Gyroscope/artifacts.xml | 29 + .../EventReceiver_light.xml | 26 + .../Eventreceiver_light_1.0.0/artifact.xml | 22 + .../Light/Eventstore_light_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_light.xml | 62 + .../Eventstream_light_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.light_1.0.0.json | 20 + .../Light_Sensor_Script.xml | 31 + .../Light/Sparkscripts_1.0.0/artifact.xml | 22 + .../resources/carbonapps/Light/artifacts.xml | 29 + .../EventReceiver_magnetic.xml | 26 + .../Eventreceiver_magnetic_1.0.0/artifact.xml | 22 + .../Eventstore_magnetic_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_magnetic.xml | 62 + .../Eventstream_magnetic_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.magnetic_1.0.0.json | 20 + .../Magnetic_Sensor_Script.xml | 30 + .../Magnetic/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Magnetic/artifacts.xml | 29 + .../EventReceiver_pressure.xml | 26 + .../Eventreceiver_pressure_1.0.0/artifact.xml | 22 + .../Eventstore_pressure_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_pressure.xml | 62 + .../Eventstream_pressure_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.pressure_1.0.0.json | 20 + .../Pressure_Sensor_Script.xml | 31 + .../Pressure/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Pressure/artifacts.xml | 29 + .../EventReceiver_proximity.xml | 26 + .../artifact.xml | 22 + .../Eventstore_proximity_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_proximity.xml | 62 + .../Eventstream_proximity_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.proximity_1.0.0.json | 20 + .../Proximity_Sensor_Script.xml | 31 + .../Proximity/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Proximity/artifacts.xml | 29 + .../EventReceiver_rotation.xml | 26 + .../Eventreceiver_rotation_1.0.0/artifact.xml | 22 + .../Eventstore_rotation_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_rotation.xml | 62 + .../Eventstream_rotation_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.rotation_1.0.0.json | 20 + .../Rotation_Sensor_Script.xml | 31 + .../Rotation/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/Rotation/artifacts.xml | 29 + .../EventReceiver_wordcount.xml | 27 + .../artifact.xml | 22 + .../Eventstore_wordcount_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_wordcount.xml | 76 + .../Eventstream_wordcount_1.0.0/artifact.xml | 23 + .../org.wso2.iot.devices.wordcount_1.0.0.json | 17 + .../Sparkscripts_1.0.0/Wordcount_Script.xml | 34 + .../WordCount/Sparkscripts_1.0.0/artifact.xml | 22 + .../carbonapps/WordCount/artifacts.xml | 29 + .../pom.xml | 205 + .../impl/AndroidSenseControllerService.java | 667 ++ .../transport/AndroidSenseMQTTConnector.java | 339 + .../service/impl/util/DeviceData.java | 15 + .../service/impl/util/SensorData.java | 44 + .../src/main/webapp/META-INF/permissions.xml | 143 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 42 + .../src/main/webapp/WEB-INF/web.xml | 57 + .../pom.xml | 205 + .../impl/AndroidSenseManagerService.java | 166 + .../manager/service/impl/util/APIUtil.java | 36 + .../src/main/webapp/META-INF/permissions.xml | 66 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 41 + .../src/main/webapp/WEB-INF/web.xml | 49 + .../pom.xml | 115 + .../constants/AndroidSenseConstants.java | 53 + .../AndroidSenseDeviceMgtPluginException.java | 56 + .../plugin/impl/AndroidSenseManager.java | 256 + .../impl/AndroidSenseManagerService.java | 101 + .../plugin/impl/dao/AndroidSenseDAO.java | 123 + .../impl/dao/impl/AndroidSenseDAOImpl.java | 198 + .../impl/dao/util/AndroidSenseUtils.java | 109 + .../dao/util/DeviceSchemaInitializer.java | 50 + .../feature/AndroidSenseFeatureManager.java | 59 + ...ndroidSenseManagementServiceComponent.java | 84 + .../pom.xml | 61 + .../src/assembly/src.xml | 36 + .../device-view.hbs | 84 + .../device-view.js | 35 + .../device-view.json | 3 + .../public/images/android-sense-icon.png | Bin 0 -> 8464 bytes .../public/images/thumb.png | Bin 0 -> 7888 bytes .../public/images/android-sense-icon.png | Bin 0 -> 8464 bytes .../public/images/myDevices_analytics.png | Bin 0 -> 286419 bytes .../public/images/publishDataView.png | Bin 0 -> 36622 bytes .../public/images/registerView.png | Bin 0 -> 17868 bytes .../public/images/selectSensorView.png | Bin 0 -> 38015 bytes .../public/images/thumb.png | Bin 0 -> 7888 bytes .../public/js/download.js | 180 + .../public/js/jquery.validate.js | 1227 +++ .../type-view.hbs | 337 + .../type-view.js | 26 + .../type-view.json | 3 + .../iot-plugins/androidsense-plugin/pom.xml | 62 + .../build.xml | 38 + .../pom.xml | 91 + .../src/assembly/src.xml | 36 + .../EventReceiver_temperature.xml | 26 + .../artifact.xml | 22 + .../Eventstore_temperature_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_temperature.xml | 62 + .../artifact.xml | 23 + ...rg.wso2.iot.devices.temperature_1.0.0.json | 20 + .../Temperature_Sensor_Script.xml | 31 + .../Sparkscripts_1.0.0/artifact.xml | 22 + .../Temperature_Sensor/artifacts.xml | 29 + .../pom.xml | 170 + .../impl/ArduinoControllerService.java | 300 + .../service/impl/dto/DeviceData.java | 35 + .../service/impl/dto/SensorData.java | 44 + .../impl/exception/ArduinoException.java | 31 + .../impl/transport/ArduinoMQTTConnector.java | 193 + .../impl/util/ArduinoServiceUtils.java | 217 + .../src/main/webapp/META-INF/permissions.xml | 87 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 48 + .../src/main/webapp/WEB-INF/web.xml | 62 + .../pom.xml | 180 + .../service/impl/ArduinoManagerService.java | 274 + .../manager/service/impl/util/APIUtil.java | 55 + .../src/main/webapp/META-INF/permissions.xml | 59 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 40 + .../src/main/webapp/WEB-INF/web.xml | 51 + .../pom.xml | 124 + .../plugin/constants/ArduinoConstants.java | 39 + .../ArduinoDeviceMgtPluginException.java | 56 + .../arduino/plugin/impl/ArduinoManager.java | 259 + .../plugin/impl/ArduinoManagerService.java | 108 + .../arduino/plugin/impl/dao/ArduinoDAO.java | 125 + .../impl/dao/impl/ArduinoDeviceDAOImpl.java | 196 + .../impl/feature/ArduinoFeatureManager.java | 59 + .../plugin/impl/util/ArduinoUtils.java | 114 + .../impl/util/DeviceSchemaInitializer.java | 50 + .../ArduinoManagementServiceComponent.java | 86 + .../pom.xml | 62 + .../src/assembly/src.xml | 36 + .../device-view.hbs | 68 + .../device-view.js | 44 + .../device-view.json | 3 + .../public/images/ardunio-icon.png | Bin 0 -> 21675 bytes .../public/images/thumb.png | Bin 0 -> 11936 bytes .../public/images/ardunio-icon.png | Bin 0 -> 21675 bytes .../public/images/myDevices_analytics.png | Bin 0 -> 147394 bytes .../public/images/schematicsGuide.png | Bin 0 -> 94571 bytes .../public/images/thumb.png | Bin 0 -> 11936 bytes .../public/js/download.js | 184 + .../public/js/jquery.validate.js | 1227 +++ .../type-view.hbs | 336 + .../type-view.json | 3 + components/iot-plugins/arduino-plugin/pom.xml | 63 + .../pom.xml | 261 + .../pom.xml | 261 + .../pom.xml | 123 + .../plugin/constants/CameraConstants.java | 27 + .../iot/camera/plugin/impl/CameraManager.java | 281 + .../plugin/impl/CameraManagerService.java | 112 + .../iot/camera/plugin/impl/dao/CameraDAO.java | 121 + .../impl/dao/impl/CameraDeviceDAOImpl.java | 237 + .../impl/util/VirtualFireAlarmUtils.java | 45 + .../CameraManagementServiceComponent.java | 98 + .../pom.xml | 62 + components/iot-plugins/camera-plugin/pom.xml | 63 + .../pom.xml | 243 + .../api/DigitalDisplayControllerService.java | 432 + .../controller/api/dto/DeviceJSON.java | 33 + .../exception/DigitalDisplayException.java | 44 + .../controller/api/model/ScreenShotModel.java | 33 + .../api/util/DigitalDisplayMQTTConnector.java | 185 + ...DigitalDisplayWebSocketServerEndPoint.java | 64 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 44 + .../src/main/webapp/WEB-INF/web.xml | 77 + .../pom.xml | 246 + .../api/DigitalDisplayManagerService.java | 243 + .../manager/api/util/APIUtil.java | 54 + .../src/main/webapp/META-INF/permissions.xml | 66 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 38 + .../src/main/webapp/WEB-INF/web.xml | 68 + .../pom.xml | 106 + .../constants/DigitalDisplayConstants.java | 37 + ...igitalDisplayDeviceMgtPluginException.java | 56 + .../plugin/impl/DigitalDisplayManager.java | 251 + .../impl/DigitalDisplayManagerService.java | 101 + .../plugin/impl/dao/DigitalDisplayDAO.java | 126 + .../dao/impl/DigitalDisplayDeviceDAOImpl.java | 194 + .../feature/DigitalDisplayFeatureManager.java | 59 + .../impl/util/DeviceSchemaInitializer.java | 50 + .../plugin/impl/util/DigitalDisplayUtils.java | 112 + ...italDisplayManagementServiceComponent.java | 85 + .../pom.xml | 62 + .../src/assembly/src.xml | 36 + .../device-view.hbs | 98 + .../device-view.js | 40 + .../device-view.json | 3 + .../public/images/default-screen.png | Bin 0 -> 55235 bytes .../public/images/display-icon.png | Bin 0 -> 4963 bytes .../public/images/thumb.png | Bin 0 -> 6246 bytes .../public/js/websocket.js | 81 + .../public/images/display-icon.png | Bin 0 -> 4963 bytes .../public/images/myDevices_analytics.png | Bin 0 -> 195921 bytes .../public/images/operations/add-resource.png | Bin 0 -> 4108 bytes .../images/operations/edit-sequence.png | Bin 0 -> 8099 bytes .../images/operations/get-content-list.png | Bin 0 -> 7366 bytes .../images/operations/get-device-status.png | Bin 0 -> 3589 bytes .../images/operations/remove-resource.png | Bin 0 -> 3929 bytes .../images/operations/restart-browser.png | Bin 0 -> 3305 bytes .../images/operations/restart-display.png | Bin 0 -> 5834 bytes .../images/operations/restart-server.png | Bin 0 -> 3293 bytes .../public/images/operations/screenshot.png | Bin 0 -> 8786 bytes .../images/operations/terminate-display.png | Bin 0 -> 4346 bytes .../images/operations/upload-content.png | Bin 0 -> 4551 bytes .../public/images/schematicsGuide.png | Bin 0 -> 393114 bytes .../public/images/thumb.png | Bin 0 -> 6246 bytes .../public/js/download.js | 191 + .../public/js/jquery.validate.js | 1227 +++ .../type-view.hbs | 292 + .../type-view.json | 3 + .../digital-display-plugin/pom.xml | 61 + .../pom.xml | 254 + .../api/impl/DroneControllerService.java | 82 + .../api/impl/DroneRealTimeService.java | 124 + .../exception/DroneAnalyzerException.java | 31 + .../transport/DroneAnalyzerXMPPConnector.java | 160 + .../impl/trasformer/MessageTransformer.java | 134 + .../impl/util/DroneAnalyzerServiceUtils.java | 96 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 40 + .../src/main/webapp/WEB-INF/web.xml | 49 + .../pom.xml | 261 + .../manager/api/impl/DroneManagerService.java | 319 + .../manager/api/impl/util/APIUtil.java | 55 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 40 + .../src/main/webapp/WEB-INF/web.xml | 62 + .../pom.xml | 108 + .../plugin/constants/DroneConstants.java | 41 + .../plugin/constants/MessageConfig.java | 40 + .../plugin/controller/DroneController.java | 32 + .../controller/impl/DroneControllerImpl.java | 73 + ...DroneAnalyzerDeviceMgtPluginException.java | 56 + .../plugin/impl/DroneAnalyzerManager.java | 250 + .../impl/DroneAnalyzerManagerService.java | 106 + .../plugin/impl/dao/DroneAnalyzerDAO.java | 126 + .../dao/impl/DroneAnalyzerDeviceDAOImpl.java | 194 + .../feature/DroneAnalyzerFeatureManager.java | 58 + .../impl/util/DeviceSchemaInitializer.java | 50 + .../plugin/impl/util/DroneAnalyzerUtils.java | 108 + ...oneAnalyzerManagementServiceComponent.java | 89 + .../pom.xml | 62 + .../src/assembly/src.xml | 36 + .../device-view.hbs | 52 + .../device-view.js | 34 + .../device-view.json | 3 + .../public/images/drone-icon.png | Bin 0 -> 46940 bytes .../public/images/thumb.png | Bin 0 -> 46940 bytes .../public/images/devices_analytics.png | Bin 0 -> 114202 bytes .../public/images/drone-icon.png | Bin 0 -> 46940 bytes .../public/images/schematicsGuide.png | Bin 0 -> 151933 bytes .../public/images/thumb.png | Bin 0 -> 48636 bytes .../public/js/download.js | 184 + .../public/js/jquery.validate.js | 1227 +++ .../type-view.hbs | 315 + .../type-view.json | 3 + .../public/css/main-app.css | 220 + .../background_drone.png | Bin 0 -> 26787 bytes .../direction_drone.png | Bin 0 -> 11617 bytes .../drone_position_controller/pitch_drone.png | Bin 0 -> 20046 bytes .../public/images/no_video_preview.gif | Bin 0 -> 2111 bytes .../3dobject_controller/3dObjectControler.js | 206 + .../js/3dobject_controller/Coordinates.js | 166 + .../OrbitAndPanControls.js | 549 + .../js/3dobject_controller/three.min.js | 724 ++ .../public/js/common/ajax_handler.js | 50 + .../public/js/common/general_handler | 101 + .../public/js/common/websocket_api | 60 + .../public/js/config/config.js | 37 + .../public/js/d3.min.js | 23 + .../public/js/download.js | 174 + .../public/js/initJs | 21 + .../public/js/jQueryRotate.js | 357 + .../public/js/jquery.validate.js | 1227 +++ .../public/js/mainHandler | 153 + .../public/js/modules/controller.js | 29 + .../public/js/modules/flight_dynamics.js | 77 + .../public/js/modules/realtime_plotting | 148 + .../statistics.hbs | 250 + .../statistics.js | 25 + .../statistics.json | 3 + .../iot-plugins/drone-analyzer-plugin/pom.xml | 61 + .../pom.xml | 139 + .../src/main/java/log4j.properties | 8 + .../device/mgt/iot/api/DeviceUsageDTO.java | 42 + .../mgt/iot/api/DevicesManagerService.java | 641 ++ .../mgt/iot/api/GroupManagerService.java | 584 + .../mgt/iot/api/PolicyManagementService.java | 507 + .../mgt/iot/api/StatsManagerService.java | 103 + .../device/mgt/iot/util/ResponsePayload.java | 108 + .../src/main/webapp/META-INF/permissions.xml | 113 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 79 + .../src/main/webapp/WEB-INF/web.xml | 27 + .../org.wso2.carbon.device.mgt.iot.ui/pom.xml | 62 + .../src/assembly/src.xml | 36 + .../devicemgt/app/conf/app-conf.json | 35 + .../public/js/validate-register.js | 163 + .../app/pages/iot.page.register/register.hbs | 75 + .../app/pages/iot.page.register/register.js | 38 + .../app/pages/iot.page.register/register.json | 6 + .../app/pages/iot.page.sign-in/sign-in.hbs | 5 + .../app/pages/iot.page.sign-in/sign-in.json | 4 + .../operation-bar.hbs | 75 + .../operation-bar.js | 31 + .../operation-bar.json | 3 + .../public/js/operation-bar.js | 56 + .../public/css/graph.css | 471 + .../public/images/map-marker-1.png | Bin 0 -> 2824 bytes .../public/images/map-marker-2.png | Bin 0 -> 2877 bytes .../iot.unit.device.stats/public/js/d3.min.js | 9488 +++++++++++++++++ .../public/js/device-stats.js | 247 + .../public/js/moment.min.js | 25 + .../public/js/rickshaw.min.js | 21 + .../app/units/iot.unit.device.stats/stats.hbs | 29 + .../app/units/iot.unit.device.stats/stats.js | 32 + .../units/iot.unit.device.stats/stats.json | 3 + .../configuration.hbs | 492 + .../configuration.json | 4 + .../public/js/platform-configuration.js | 856 ++ .../app/units/iot.unit.policy.edit/edit.hbs | 246 + .../app/units/iot.unit.policy.edit/edit.js | 25 + .../app/units/iot.unit.policy.edit/edit.json | 3 + .../public/css/codemirror.css | 342 + .../public/js/codemirror.js | 8720 +++++++++++++++ .../public/js/policy-edit.js | 729 ++ .../iot.unit.policy.edit/public/js/sql.js | 310 + .../public/css/codemirror.css | 342 + .../public/js/codemirror.js | 8720 +++++++++++++++ .../public/js/policy-view.js | 128 + .../iot.unit.policy.view/public/js/sql.js | 310 + .../app/units/iot.unit.policy.view/view.hbs | 95 + .../app/units/iot.unit.policy.view/view.js | 25 + .../app/units/iot.unit.policy.view/view.json | 3 + .../public/css/codemirror.css | 342 + .../public/js/codemirror.js | 8720 +++++++++++++++ .../public/js/policy-create.js | 670 ++ .../iot.unit.policy.wizard/public/js/sql.js | 310 + .../units/iot.unit.policy.wizard/wizard.hbs | 255 + .../units/iot.unit.policy.wizard/wizard.js | 47 + .../units/iot.unit.policy.wizard/wizard.json | 3 + .../units/iot.unit.ui.header.logo/logo.hbs | 1 + .../units/iot.unit.ui.header.logo/logo.json | 5 + .../org.wso2.carbon.device.mgt.iot/pom.xml | 213 + .../DeviceManagementConfigurationManager.java | 118 + .../server/datasource/ControlQueue.java | 229 + .../datasource/ControlQueuesConfig.java | 82 + .../DeviceManagementConfiguration.java | 74 + .../server/datasource/ObjectFactory.java | 69 + .../mgt/iot/controlqueue/mqtt/MqttConfig.java | 81 + .../iot/controlqueue/xmpp/XmppAccount.java | 60 + .../mgt/iot/controlqueue/xmpp/XmppConfig.java | 93 + .../controlqueue/xmpp/XmppServerClient.java | 352 + .../exception/DeviceControllerException.java | 42 + .../mgt/iot/exception/IoTException.java | 43 + .../exception/NotImplementedException.java | 43 + .../iot/exception/UnauthorizedException.java | 39 + .../mgt/iot/internal/IoTCommonDataHolder.java | 54 + .../IotDeviceManagementServiceComponent.java | 100 + .../device/mgt/iot/mqtt/PolicyPush.java | 66 + .../mgt/iot/sensormgt/DeviceRecord.java | 43 + .../mgt/iot/sensormgt/SensorDataManager.java | 137 + .../mgt/iot/sensormgt/SensorRecord.java | 46 + .../iot/service/IoTServerStartupListener.java | 41 + .../mgt/iot/transport/CommunicationUtils.java | 219 + .../mgt/iot/transport/TransportHandler.java | 108 + .../transport/TransportHandlerException.java | 56 + .../mgt/iot/transport/TransportUtils.java | 296 + .../transport/mqtt/MQTTTransportHandler.java | 402 + .../transport/xmpp/XMPPTransportHandler.java | 376 + .../carbon/device/mgt/iot/util/IoTUtil.java | 127 + .../mgt/iot/util/IotDeviceManagementUtil.java | 346 + .../device/mgt/iot/util/ZipArchive.java | 49 + .../carbon/device/mgt/iot/util/ZipUtil.java | 100 + .../iot-plugins/iot-base-plugin/pom.xml | 60 + components/iot-plugins/pom.xml | 67 + .../build.xml | 38 + .../pom.xml | 92 + .../src/assembly/src.xml | 36 + .../EventReceiver_temperature.xml | 26 + .../artifact.xml | 22 + .../Eventstore_temperature_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_temperature.xml | 62 + .../artifact.xml | 23 + ...rg.wso2.iot.devices.temperature_1.0.0.json | 20 + .../Temperature_Sensor_Script.xml | 31 + .../Sparkscripts_1.0.0/artifact.xml | 22 + .../Temperature_Sensor/artifacts.xml | 29 + .../pom.xml | 158 + .../impl/RaspberryPiControllerService.java | 295 + .../service/impl/dto/DeviceData.java | 36 + .../service/impl/dto/SensorData.java | 44 + .../impl/exception/RaspberrypiException.java | 31 + .../transport/RaspberryPiMQTTConnector.java | 195 + .../impl/util/RaspberrypiServiceUtils.java | 228 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 45 + .../src/main/webapp/WEB-INF/web.xml | 54 + .../pom.xml | 166 + .../impl/RaspberryPiManagerService.java | 323 + .../manager/service/impl/util/APIUtil.java | 55 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 43 + .../src/main/webapp/WEB-INF/web.xml | 50 + .../pom.xml | 124 + .../constants/RaspberrypiConstants.java | 39 + .../RaspberrypiDeviceMgtPluginException.java | 56 + .../plugin/impl/RaspberrypiManager.java | 252 + .../impl/RaspberrypiManagerService.java | 108 + .../plugin/impl/dao/RaspberrypiDAO.java | 124 + .../dao/impl/RaspberrypiDeviceDAOImpl.java | 191 + .../feature/RaspberrypiFeatureManager.java | 58 + .../impl/util/DeviceSchemaInitializer.java | 50 + .../plugin/impl/util/RaspberrypiUtils.java | 111 + ...RaspberrypiManagementServiceComponent.java | 85 + .../pom.xml | 62 + .../src/assembly/src.xml | 36 + .../device-view.hbs | 68 + .../device-view.js | 35 + .../device-view.json | 3 + .../public/images/respberry-icon.png | Bin 0 -> 40558 bytes .../public/images/thumb.png | Bin 0 -> 44816 bytes .../public/images/myDevices_analytics.png | Bin 0 -> 220158 bytes .../public/images/respberry-icon.png | Bin 0 -> 40558 bytes .../public/images/schematicsGuide.png | Bin 0 -> 142048 bytes .../public/images/thumb.png | Bin 0 -> 44816 bytes .../public/js/download.js | 183 + .../public/js/jquery.validate.js | 1227 +++ .../type-view.hbs | 324 + .../type-view.json | 3 + .../iot-plugins/raspberrypi-plugin/pom.xml | 62 + .../pom.xml | 255 + .../agent/advanced/Bootstrap.java | 36 + .../http/FireAlarmHTTPCommunicator.java | 495 + .../mqtt/FireAlarmMQTTCommunicator.java | 294 + .../xmpp/FireAlarmXMPPCommunicator.java | 265 + .../advanced/core/AgentConfiguration.java | 155 + .../agent/advanced/core/AgentConstants.java | 135 + .../agent/advanced/core/AgentManager.java | 377 + .../advanced/core/AgentUtilOperations.java | 371 + .../enrollment/EnrollmentManager.java | 440 + .../AgentCoreOperationException.java | 57 + .../agent/advanced/sidhdhi/SidhdhiQuery.java | 205 + .../transport/CommunicationUtils.java | 226 + .../advanced/transport/TransportHandler.java | 47 + .../transport/TransportHandlerException.java | 56 + .../advanced/transport/TransportUtils.java | 302 + .../transport/http/HTTPTransportHandler.java | 91 + .../transport/mqtt/MQTTTransportHandler.java | 360 + .../transport/xmpp/XMPPTransportHandler.java | 366 + .../virtual/VirtualHardwareManager.java | 218 + .../agent/advanced/virtual/ui/AgentUI.java | 1085 ++ .../src/main/resources/alarm-off.gif | Bin 0 -> 4265 bytes .../src/main/resources/alarm-on.gif | Bin 0 -> 12067 bytes .../src/main/resources/cep_query.txt | 11 + .../main/resources/deviceConfig.properties | 33 + .../src/main/resources/fireAlarmSound.mid | Bin 0 -> 6719 bytes .../src/main/ui/build.xml | 73 + .../src/main/ui/manifest.mf | 3 + .../src/main/ui/nbproject/build-impl.xml | 1413 +++ .../src/main/ui/nbproject/genfiles.properties | 8 + .../ui/nbproject/private/private.properties | 2 + .../src/main/ui/nbproject/private/private.xml | 9 + .../src/main/ui/nbproject/project.properties | 73 + .../src/main/ui/nbproject/project.xml | 15 + .../src/main/ui/src/bulb-on.jpg | Bin 0 -> 6942 bytes .../mgt/iot/agent/virtual/VirtualAgentUI.java | 37 + .../mgt/iot/agent/virtual/ui/AgentUI.form | 830 ++ .../mgt/iot/agent/virtual/ui/AgentUI.java | 758 ++ .../pom.xml | 232 + .../iot/virtualfirealarm/agent/Bootstrap.java | 36 + .../http/FireAlarmHTTPCommunicator.java | 495 + .../mqtt/FireAlarmMQTTCommunicator.java | 265 + .../xmpp/FireAlarmXMPPCommunicator.java | 265 + .../agent/core/AgentConfiguration.java | 155 + .../agent/core/AgentConstants.java | 109 + .../agent/core/AgentManager.java | 347 + .../agent/core/AgentUtilOperations.java | 280 + .../agent/enrollment/EnrollmentManager.java | 436 + .../AgentCoreOperationException.java | 57 + .../agent/transport/CommunicationUtils.java | 225 + .../agent/transport/TransportHandler.java | 47 + .../transport/TransportHandlerException.java | 56 + .../agent/transport/TransportUtils.java | 302 + .../transport/http/HTTPTransportHandler.java | 91 + .../transport/mqtt/MQTTTransportHandler.java | 360 + .../transport/xmpp/XMPPTransportHandler.java | 366 + .../agent/virtual/VirtualHardwareManager.java | 213 + .../agent/virtual/ui/AgentUI.java | 954 ++ .../src/main/resources/alarm-off.gif | Bin 0 -> 4265 bytes .../src/main/resources/alarm-on.gif | Bin 0 -> 12067 bytes .../main/resources/deviceConfig.properties | 33 + .../src/main/resources/fireAlarmSound.mid | Bin 0 -> 6719 bytes .../src/main/ui/build.xml | 73 + .../src/main/ui/manifest.mf | 3 + .../src/main/ui/nbproject/build-impl.xml | 1413 +++ .../src/main/ui/nbproject/genfiles.properties | 8 + .../ui/nbproject/private/private.properties | 2 + .../src/main/ui/nbproject/private/private.xml | 9 + .../src/main/ui/nbproject/project.properties | 73 + .../src/main/ui/nbproject/project.xml | 15 + .../src/main/ui/src/bulb-on.jpg | Bin 0 -> 6942 bytes .../mgt/iot/agent/virtual/VirtualAgentUI.java | 37 + .../mgt/iot/agent/virtual/ui/AgentUI.form | 803 ++ .../mgt/iot/agent/virtual/ui/AgentUI.java | 744 ++ .../build.xml | 38 + .../pom.xml | 92 + .../src/assembly/src.xml | 36 + .../EventReceiver_temperature.xml | 26 + .../artifact.xml | 22 + .../Eventstore_temperature_1.0.0/artifact.xml | 22 + .../org_wso2_iot_devices_temperature.xml | 62 + .../artifact.xml | 23 + ...rg.wso2.iot.devices.temperature_1.0.0.json | 20 + .../Temperature_Sensor_Script.xml | 31 + .../Sparkscripts_1.0.0/artifact.xml | 22 + .../Temperature_Sensor/artifacts.xml | 29 + .../pom.xml | 262 + .../VirtualFireAlarmControllerService.java | 614 ++ .../service/impl/dto/DeviceData.java | 36 + .../service/impl/dto/SensorData.java | 44 + .../exception/VirtualFireAlarmException.java | 31 + .../VirtualFireAlarmMQTTConnector.java | 309 + .../VirtualFireAlarmXMPPConnector.java | 293 + .../service/impl/util/SecurityManager.java | 254 + .../util/VirtualFireAlarmServiceUtils.java | 366 + .../service/impl/util/scep/ContentType.java | 26 + .../service/impl/util/scep/SCEPOperation.java | 39 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 52 + .../src/main/webapp/WEB-INF/web.xml | 65 + .../pom.xml | 271 + .../impl/VirtualFireAlarmManagerService.java | 312 + .../manager/service/impl/util/APIUtil.java | 55 + .../webapp/META-INF/webapp-classloading.xml | 33 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 39 + .../src/main/webapp/WEB-INF/web.xml | 65 + .../pom.xml | 124 + .../constants/VirtualFireAlarmConstants.java | 40 + ...tualFirealarmDeviceMgtPluginException.java | 56 + .../plugin/impl/VirtualFireAlarmManager.java | 256 + .../impl/VirtualFireAlarmManagerService.java | 107 + .../plugin/impl/dao/VirtualFireAlarmDAO.java | 125 + .../impl/VirtualFireAlarmDeviceDAOImpl.java | 196 + .../VirtualFirealarmFeatureManager.java | 58 + .../impl/util/DeviceSchemaInitializer.java | 50 + .../impl/util/VirtualFireAlarmUtils.java | 111 + ...alFirealarmManagementServiceComponent.java | 84 + .../pom.xml | 62 + .../src/assembly/src.xml | 36 + .../device-view.hbs | 105 + .../device-view.js | 35 + .../device-view.json | 3 + .../public/images/firealarm-icon.png | Bin 0 -> 28584 bytes .../public/images/thumb.png | Bin 0 -> 31021 bytes .../policy-edit.hbs | 1 + .../policy-edit.json | 3 + .../policy-view.hbs | 1 + .../policy-view.json | 3 + .../policy-wizard.hbs | 1 + .../policy-wizard.json | 3 + .../public/images/firealarm-icon.png | Bin 0 -> 28584 bytes .../public/images/myDevices_analytics.png | Bin 0 -> 759452 bytes .../public/images/schematicsGuide.png | Bin 0 -> 52343 bytes .../public/images/thumb.png | Bin 0 -> 31021 bytes .../public/js/download.js | 184 + .../public/js/jquery.validate.js | 1227 +++ .../type-view.hbs | 297 + .../type-view.json | 3 + .../virtual-fire-alarm-plugin/pom.xml | 64 + .../pom.xml | 83 - .../key/mgt/handler/valve/HandlerUtil.java | 141 - .../valve/OAuthTokenValidatorValve.java | 144 - .../pom.xml | 180 + .../android/ConfigurationMgtService.java | 161 + .../android/DeviceManagementService.java | 183 + .../services/android/EnrollmentService.java | 153 + .../services/android/OperationMgtService.java | 931 ++ .../services/android/PolicyMgtService.java | 92 + .../android/bean/AndroidOperation.java | 36 + .../android/bean/ApplicationInstallation.java | 55 + .../bean/ApplicationUninstallation.java | 64 + .../android/bean/BlacklistApplications.java | 39 + .../mdm/services/android/bean/Camera.java | 37 + .../android/bean/DeviceEncryption.java | 37 + .../services/android/bean/Disenrollment.java | 35 + .../mdm/services/android/bean/LockCode.java | 37 + .../services/android/bean/Notification.java | 37 + .../services/android/bean/PasscodePolicy.java | 91 + .../mdm/services/android/bean/WebClip.java | 55 + .../mdm/services/android/bean/Wifi.java | 46 + .../mdm/services/android/bean/WipeData.java | 37 + .../ApplicationInstallationBeanWrapper.java | 47 + .../ApplicationUninstallationBeanWrapper.java | 47 + .../BlacklistApplicationsBeanWrapper.java | 47 + .../bean/wrapper/CameraBeanWrapper.java | 47 + .../wrapper/DisenrollmentBeanWrapper.java | 44 + .../bean/wrapper/EncryptionBeanWrapper.java | 47 + .../bean/wrapper/LockCodeBeanWrapper.java | 47 + .../bean/wrapper/NotificationBeanWrapper.java | 47 + .../wrapper/PasswordPolicyBeanWrapper.java | 47 + .../bean/wrapper/WebClipBeanWrapper.java | 47 + .../android/bean/wrapper/WifiBeanWrapper.java | 47 + .../bean/wrapper/WipeDataBeanWrapper.java | 47 + .../services/android/common/ErrorHandler.java | 35 + .../services/android/common/ErrorMessage.java | 41 + .../common/GsonMessageBodyHandler.java | 97 + .../exception/AndroidAgentException.java | 63 + .../exception/AndroidOperationException.java | 37 + .../exception/BadRequestException.java | 36 + .../OperationConfigurationException.java | 37 + .../android/util/AndroidAPIUtils.java | 215 + .../android/util/AndroidConstants.java | 114 + .../android/util/AndroidDeviceUtils.java | 98 + .../services/android/util/DeviceIDHolder.java | 48 + .../mdm/services/android/util/Message.java | 88 + .../src/main/webapp/META-INF/permissions.xml | 315 + .../webapp/META-INF/webapp-classloading.xml | 35 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 80 + .../src/main/webapp/WEB-INF/web.xml | 77 + .../src/main/webapp/servicelist.css | 117 + .../pom.xml | 176 + .../impl/AndroidDeviceManagementService.java | 109 + .../android/impl/AndroidDeviceManager.java | 356 + .../android/impl/AndroidFeatureManager.java | 244 + .../impl/AndroidPolicyMonitoringService.java | 100 + .../android/impl/dao/AndroidDAOFactory.java | 120 + .../AndroidFeatureManagementDAOException.java | 79 + .../impl/dao/impl/AndroidDeviceDAOImpl.java | 265 + .../impl/dao/impl/AndroidFeatureDAOImpl.java | 285 + .../mobile/android/impl/gcm/GCMResult.java | 53 + .../mobile/android/impl/gcm/GCMService.java | 64 + .../mgt/mobile/android/impl/gcm/GCMUtil.java | 204 + .../impl/util/AndroidPluginConstants.java | 47 + .../android/impl/util/AndroidPluginUtils.java | 58 + .../android/impl/util/AndroidUtils.java | 31 + .../AndroidDeviceManagementDataHolder.java | 67 + ...droidDeviceManagementServiceComponent.java | 137 + .../mobile-plugins/android-plugin/pom.xml | 59 + .../pom.xml | 205 + .../wso2/carbon/mdm/api/Authentication.java | 36 + .../wso2/carbon/mdm/api/Configuration.java | 98 + .../carbon/mdm/api/DeviceNotification.java | 108 + .../java/org/wso2/carbon/mdm/api/Feature.java | 62 + .../java/org/wso2/carbon/mdm/api/License.java | 99 + .../org/wso2/carbon/mdm/api/MobileDevice.java | 218 + .../org/wso2/carbon/mdm/api/Operation.java | 225 + .../java/org/wso2/carbon/mdm/api/Policy.java | 475 + .../java/org/wso2/carbon/mdm/api/Profile.java | 89 + .../java/org/wso2/carbon/mdm/api/Role.java | 422 + .../java/org/wso2/carbon/mdm/api/User.java | 786 ++ .../carbon/mdm/api/common/ErrorHandler.java | 32 + .../carbon/mdm/api/common/ErrorMessage.java} | 23 +- .../mdm/api/common/MDMAPIException.java | 59 + .../api/context/DeviceOperationContext.java | 54 + .../wso2/carbon/mdm/api/util/MDMAPIUtils.java | 255 + .../mdm/api/util/MDMAndroidOperationUtil.java | 116 + .../carbon/mdm/api/util/MDMAppConstants.java | 55 + .../mdm/api/util/MDMIOSOperationUtil.java | 106 + .../carbon/mdm/api/util/ResponsePayload.java | 106 + .../carbon/mdm/beans/ApplicationWrapper.java | 63 + .../org/wso2/carbon/mdm/beans/MobileApp.java | 130 + .../carbon/mdm/beans/MobileAppTypes.java} | 12 +- .../wso2/carbon/mdm/beans/PolicyWrapper.java | 126 + .../beans/PriorityUpdatedPolicyWrapper.java | 41 + .../org/wso2/carbon/mdm/beans/Profile.java | 107 + .../wso2/carbon/mdm/beans/ProfileFeature.java | 85 + .../wso2/carbon/mdm/beans/RoleWrapper.java | 59 + .../mdm/beans/UserCredentialWrapper.java | 53 + .../wso2/carbon/mdm/beans/UserWrapper.java | 87 + .../beans/android/AppStoreApplication.java | 52 + .../beans/android/EnterpriseApplication.java | 61 + .../mdm/beans/android/WebApplication.java | 61 + .../mdm/beans/ios/AppStoreApplication.java | 86 + .../mdm/beans/ios/EnterpriseApplication.java | 83 + .../mdm/beans/ios/RemoveApplication.java | 24 + .../wso2/carbon/mdm/beans/ios/WebClip.java | 60 + .../org/wso2/carbon/mdm/util/Constants.java | 30 + .../org/wso2/carbon/mdm/util/MDMUtil.java | 60 + .../mdm/util/SetReferenceTransformer.java | 60 + .../java/org/wso2/mdm/common/Application.java | 119 + .../mdm/common/GsonMessageBodyHandler.java | 94 + .../src/main/webapp/META-INF/permissions.xml | 565 + .../webapp/META-INF/webapp-classloading.xml | 35 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 144 + .../src/main/webapp/WEB-INF/web.xml | 74 + .../pom.xml | 62 + .../src/assembly/src.xml | 36 + .../configuration.hbs | 5 + .../configuration.json | 5 + .../operation-bar.hbs | 7 + .../operation-bar.json | 4 + .../public/js/operation-bar.js | 195 + .../templates/hidden-operations-android.hbs | 304 + .../templates/hidden-operations-ios.hbs | 366 + .../public/templates/operations.hbs | 156 + .../operation-mod.hbs | 3 + .../operation-mod.json | 4 + .../public/js/operation-mod.js | 1228 +++ .../configuration.hbs | 484 + .../configuration.js | 9 + .../configuration.json | 4 + .../public/js/platform-configuration.js | 878 ++ .../app/units/mdm.unit.policy.edit/edit.hbs | 223 + .../app/units/mdm.unit.policy.edit/edit.js | 26 + .../app/units/mdm.unit.policy.edit/edit.json | 3 + .../public/js/policy-create.js | 2321 ++++ .../templates/hidden-operations-android.hbs | 457 + .../templates/hidden-operations-ios.hbs | 2923 +++++ .../templates/hidden-operations-windows.hbs | 460 + .../public/js/policy-view.js | 2256 ++++ .../templates/hidden-operations-android.hbs | 439 + .../templates/hidden-operations-ios.hbs | 2923 +++++ .../templates/hidden-operations-windows.hbs | 460 + .../app/units/mdm.unit.policy.view/view.hbs | 87 + .../app/units/mdm.unit.policy.view/view.js | 25 + .../app/units/mdm.unit.policy.view/view.json | 3 + .../public/js/policy-create.js | 2355 ++++ .../templates/hidden-operations-android.hbs | 458 + .../templates/hidden-operations-ios.hbs | 2923 +++++ .../templates/hidden-operations-windows.hbs | 460 + .../units/mdm.unit.policy.wizard/wizard.hbs | 278 + .../units/mdm.unit.policy.wizard/wizard.js | 37 + .../units/mdm.unit.policy.wizard/wizard.json | 3 + .../units/mdm.unit.ui.header.logo/logo.hbs | 1 + .../units/mdm.unit.ui.header.logo/logo.json | 5 + .../pom.xml | 81 + .../url/printer/URLPrinterStartupHandler.java | 64 + .../internal/URLPrinterDataHolder.java | 42 + ...PrinterStartupHandlerServiceComponent.java | 73 + .../org.wso2.carbon.device.mgt.mobile/pom.xml | 172 + .../AbstractMobileOperationManager.java | 41 + .../device/mgt/mobile/DataSourceListener.java | 25 + .../DataSourceNotAvailableException.java | 52 + .../MobileDeviceMgtPluginException.java | 57 + .../mobile/common/MobilePluginConstants.java | 29 + .../MobileDeviceConfigurationManager.java | 79 + .../config/MobileDeviceManagementConfig.java | 42 + .../MobileDeviceManagementRepository.java | 57 + .../datasource/DataSourceConfigAdapter.java | 51 + .../datasource/JNDILookupDefinition.java | 79 + .../datasource/MobileDataSourceConfig.java | 51 + .../MobileDataSourceConfigurations.java | 41 + ...tractMobileDeviceManagementDAOFactory.java | 102 + .../mgt/mobile/dao/MobileDeviceDAO.java | 74 + .../MobileDeviceManagementDAOException.java | 80 + .../dao/MobileDeviceManagementDAOFactory.java | 27 + .../mgt/mobile/dao/MobileFeatureDAO.java | 110 + .../mobile/dao/impl/MobileFeatureDAOImpl.java | 336 + .../util/MobileDeviceManagementDAOUtil.java | 139 + .../device/mgt/mobile/dto/MobileDevice.java | 125 + .../dto/MobileDeviceOperationMapping.java | 86 + .../device/mgt/mobile/dto/MobileFeature.java | 73 + .../mgt/mobile/dto/MobileFeatureProperty.java | 45 + .../mgt/mobile/dto/MobileOperation.java | 64 + .../mobile/dto/MobileOperationProperty.java | 54 + .../MobileDeviceManagementDataHolder.java | 48 + ...obileDeviceManagementServiceComponent.java | 137 + ...bileDeviceManagementSchemaInitializer.java | 62 + .../util/MobileDeviceManagementUtil.java | 320 + .../MobileDeviceManagementConfigTests.java | 141 + .../mgt/mobile/impl/common/DBTypes.java | 29 + .../impl/common/TestDBConfiguration.java | 90 + .../impl/common/TestDBConfigurations.java | 39 + .../impl/dao/util/MobileDatabaseUtils.java | 111 + .../malformed-mobile-config-no-api-config.xml | 41 + ...-mobile-config-no-api-publisher-config.xml | 42 + ...malformed-mobile-config-no-apis-config.xml | 42 + .../malformed-mobile-config-no-ds-config.xml | 42 + ...malformed-mobile-config-no-jndi-config.xml | 42 + .../malformed-mobile-config-no-mgt-repo.xml | 42 + .../MobileDeviceManagementConfigSchema.xsd | 69 + .../src/test/resources/log4j.properties | 33 + .../src/test/resources/sql/h2.sql | 54 + .../src/test/resources/testdbconfig.xml | 24 + .../src/test/resources/testng.xml | 27 + .../mobile-plugins/mobile-base-plugin/pom.xml | 62 + .../{key-mgt => mobile-plugins}/pom.xml | 17 +- .../pom.xml | 309 + .../windows/common/PluginConstants.java | 293 + .../windows/common/SyncmlCommandType.java | 34 + .../windows/common/beans/CacheEntry.java | 52 + .../windows/common/beans/Token.java | 35 + .../common/beans/WindowsPluginProperties.java | 92 + .../exceptions/AuthenticationException.java | 58 + .../exceptions/BadRequestException.java | 36 + .../CertificateGenerationException.java | 58 + .../exceptions/FileOperationException.java | 58 + .../KeyStoreGenerationException.java | 58 + .../common/exceptions/MDMAPIException.java | 60 + .../SyncmlMessageFormatException.java | 57 + .../exceptions/SyncmlOperationException.java | 58 + .../exceptions/WAPProvisioningException.java | 58 + .../WindowsConfigurationException.java | 61 + .../WindowsDeviceEnrolmentException.java | 59 + .../WindowsOperationsException.java | 37 + .../common/util/AuthenticationInfo.java | 62 + .../windows/common/util/BSTValidator.java | 162 + .../ConfigInitializerContextListener.java | 138 + .../windows/common/util/DeviceIDHolder.java | 48 + .../windows/common/util/DeviceUtil.java | 81 + .../windows/common/util/ErrorHandler.java | 38 + .../windows/common/util/ErrorMessage.java | 39 + .../common/util/GsonMessageBodyHandler.java | 98 + .../windows/common/util/Message.java | 49 + .../common/util/SOAPSecurityHandler.java | 63 + .../common/util/UsernameTokenValidator.java | 134 + .../windows/common/util/WindowsAPIUtils.java | 210 + .../common/util/WindowsDeviceUtils.java | 85 + .../windows/operations/AddTag.java | 68 + .../windows/operations/Alert.java | 63 + .../windows/operations/AtomicTag.java | 85 + .../windows/operations/ChallengeTag.java | 46 + .../windows/operations/Credential.java | 60 + .../windows/operations/DeleteTag.java | 68 + .../windows/operations/ExecuteTag.java | 69 + .../windows/operations/Get.java | 71 + .../windows/operations/Item.java | 90 + .../windows/operations/MetaTag.java | 88 + .../windows/operations/Replace.java | 70 + .../windows/operations/Results.java | 96 + .../windows/operations/SequenceTag.java | 117 + .../windows/operations/Source.java | 63 + .../windows/operations/Status.java | 144 + .../windows/operations/SyncmlBody.java | 144 + .../windows/operations/SyncmlDocument.java | 55 + .../windows/operations/SyncmlHeader.java | 114 + .../windows/operations/Target.java | 63 + .../operations/WindowsOperationException.java | 58 + .../windows/operations/util/Constants.java | 98 + .../windows/operations/util/DeviceInfo.java | 92 + .../operations/util/OperationCode.java | 112 + .../operations/util/OperationReply.java | 772 ++ .../operations/util/OperationUtils.java | 505 + .../operations/util/SyncmlCredentials.java | 70 + .../operations/util/SyncmlGenerator.java | 100 + .../windows/operations/util/SyncmlParser.java | 458 + .../services/adminoperations/Operations.java | 57 + .../adminoperations/beans/Device.java | 36 + .../adminoperations/beans/Disenrollment.java | 42 + .../beans/OperationRequest.java | 49 + .../beans/OperationResponse.java | 48 + .../beans/StorageEncryption.java | 36 + .../wrapper/DisenrollmentBeanWrapper.java | 50 + .../beans/wrapper/EncryptBeanWrapper.java | 48 + .../adminoperations/impl/OperationsImpl.java | 242 + .../adminoperations/util/OperationStore.java | 112 + .../windows/services/authbst/BSTProvider.java | 40 + .../services/authbst/beans/Credentials.java | 87 + .../authbst/impl/BSTProviderImpl.java | 131 + .../ConfigurationMgtService.java | 181 + .../DeviceManagementService.java | 158 + .../services/discovery/DiscoveryService.java | 62 + .../discovery/beans/DiscoveryRequest.java | 61 + .../discovery/beans/DiscoveryResponse.java | 73 + .../discovery/beans/package-info.java | 22 + .../discovery/impl/DiscoveryServiceImpl.java | 112 + .../policymgtservice/PolicyMgtService.java | 71 + .../services/syncml/SyncmlService.java | 48 + .../services/syncml/beans/BasicOperation.java | 35 + .../services/syncml/beans/PasscodePolicy.java | 107 + .../services/syncml/beans/Profile.java | 62 + .../windows/services/syncml/beans/Wifi.java | 107 + .../syncml/impl/SyncmlServiceImpl.java | 462 + .../services/syncml/util/PolicyManager.java | 54 + .../services/syncml/util/SyncmlUtils.java | 49 + .../wstep/CertificateEnrollmentService.java | 62 + .../wstep/beans/AdditionalContext.java | 48 + .../wstep/beans/BinarySecurityToken.java | 67 + .../services/wstep/beans/ContextItem.java | 44 + .../wstep/beans/RequestSecurityToken.java | 42 + .../beans/RequestSecurityTokenResponse.java | 68 + .../wstep/beans/RequestedSecurityToken.java | 42 + .../services/wstep/beans/package-info.java | 27 + .../CertificateEnrollmentServiceImpl.java | 381 + .../wstep/util/CertificateSigningService.java | 143 + .../wstep/util/KeyStoreGenerator.java | 93 + .../services/wstep/util/MessageHandler.java | 207 + .../CertificateEnrollmentPolicyService.java | 70 + .../services/xcep/beans/Attributes.java | 451 + .../windows/services/xcep/beans/CA.java | 166 + .../services/xcep/beans/CACollection.java | 83 + .../xcep/beans/CAReferenceCollection.java | 83 + .../windows/services/xcep/beans/CAURI.java | 168 + .../services/xcep/beans/CAURICollection.java | 83 + .../beans/CertificateEnrollmentPolicy.java | 149 + .../xcep/beans/CertificateValidity.java | 99 + .../windows/services/xcep/beans/Client.java | 136 + .../services/xcep/beans/CryptoProviders.java | 87 + .../xcep/beans/EnrollmentPermission.java | 82 + .../services/xcep/beans/Extension.java | 108 + .../xcep/beans/ExtensionCollection.java | 87 + .../xcep/beans/FilterOIDCollection.java | 87 + .../services/xcep/beans/GetPolicies.java | 101 + .../xcep/beans/GetPoliciesResponse.java | 126 + .../xcep/beans/KeyArchivalAttributes.java | 86 + .../windows/services/xcep/beans/OID.java | 166 + .../services/xcep/beans/OIDCollection.java | 83 + .../xcep/beans/OIDReferenceCollection.java | 83 + .../services/xcep/beans/ObjectFactory.java | 253 + .../services/xcep/beans/PolicyCollection.java | 84 + .../xcep/beans/PrivateKeyAttributes.java | 193 + .../services/xcep/beans/RARequirements.java | 119 + .../services/xcep/beans/RequestFilter.java | 107 + .../windows/services/xcep/beans/Response.java | 204 + .../windows/services/xcep/beans/Revision.java | 85 + .../xcep/beans/SupersededPolicies.java | 83 + .../services/xcep/beans/package-info.java | 23 + ...ertificateEnrollmentPolicyServiceImpl.java | 101 + .../src/main/resources/properties.xml | 26 + .../src/main/resources/wap-provisioning.xml | 87 + .../src/main/resources/wso2mdm.jks | Bin 0 -> 9485 bytes .../src/main/webapp/META-INF/permissions.xml | 142 + .../webapp/META-INF/webapp-classloading.xml | 35 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 207 + .../src/main/webapp/WEB-INF/web.xml | 63 + .../src/main/webapp/servicelist.css | 125 + .../pom.xml | 176 + .../impl/WindowsDeviceManagementService.java | 108 + .../windows/impl/WindowsDeviceManager.java | 308 + .../windows/impl/WindowsFeatureManager.java | 196 + .../impl/WindowsPolicyMonitoringService.java | 73 + .../windows/impl/dao/WindowsDAOFactory.java | 131 + .../WindowsFeatureManagementDAOException.java | 80 + .../impl/dao/impl/WindowsDeviceDAOImpl.java | 255 + .../impl/dao/impl/WindowsFeatureDAOImpl.java | 271 + .../impl/util/WindowsPluginConstants.java | 48 + .../windows/impl/util/WindowsPluginUtils.java | 58 + .../windows/impl/util/WindowsUtils.java | 35 + .../WindowsDeviceManagementDataHolder.java | 47 + ...ndowsDeviceManagementServiceComponent.java | 121 + .../mobile-plugins/windows-plugin/pom.xml | 61 + pom.xml | 566 +- 996 files changed, 166704 insertions(+), 407 deletions(-) create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/build.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/pom.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/assembly/src.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/EventReceiver_accelerometer.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/org_wso2_iot_devices_accelerometer.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/org.wso2.iot.devices.accelerometer_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/Accelerometer_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/EventReceiver_battery.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/org_wso2_iot_devices_battery.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/org.wso2.iot.devices.battery_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/Battery_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/EventReceiver_gps.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/org_wso2_iot_devices_gps.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/org.wso2.iot.devices.gps_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/GPS_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/EventReceiver_gravity.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/org_wso2_iot_devices_gravity.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/org.wso2.iot.devices.gravity_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/Gravity_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/EventReceiver_gyroscope.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/org_wso2_iot_devices_gyroscope.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/org.wso2.iot.devices.gyroscope_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/Gyroscope_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/EventReceiver_light.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/org_wso2_iot_devices_light.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/org.wso2.iot.devices.light_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/Light_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/EventReceiver_magnetic.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/org_wso2_iot_devices_magnetic.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/org.wso2.iot.devices.magnetic_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/Magnetic_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/EventReceiver_pressure.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/org_wso2_iot_devices_pressure.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/org.wso2.iot.devices.pressure_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/Pressure_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/EventReceiver_proximity.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/org_wso2_iot_devices_proximity.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/org.wso2.iot.devices.proximity_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/Proximity_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/EventReceiver_rotation.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/org_wso2_iot_devices_rotation.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/org.wso2.iot.devices.rotation_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/Rotation_Sensor_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/EventReceiver_wordcount.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/org_wso2_iot_devices_wordcount.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/org.wso2.iot.devices.wordcount_1.0.0.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/Wordcount_Script.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/artifacts.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/pom.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/AndroidSenseControllerService.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/transport/AndroidSenseMQTTConnector.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/DeviceData.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/SensorData.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/permissions.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/pom.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/AndroidSenseManagerService.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/util/APIUtil.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/permissions.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/pom.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/constants/AndroidSenseConstants.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/exception/AndroidSenseDeviceMgtPluginException.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManager.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManagerService.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/AndroidSenseDAO.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/impl/AndroidSenseDAOImpl.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/AndroidSenseUtils.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/DeviceSchemaInitializer.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/feature/AndroidSenseFeatureManager.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/internal/AndroidSenseManagementServiceComponent.java create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/pom.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.hbs create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.js create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.json create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/public/images/android-sense-icon.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/public/images/thumb.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/android-sense-icon.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/myDevices_analytics.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/publishDataView.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/registerView.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/selectSensorView.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/thumb.png create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/download.js create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/jquery.validate.js create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.hbs create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.js create mode 100644 components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.json create mode 100644 components/iot-plugins/androidsense-plugin/pom.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/build.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/pom.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/assembly/src.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/pom.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/ArduinoControllerService.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/DeviceData.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/SensorData.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/exception/ArduinoException.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/transport/ArduinoMQTTConnector.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/util/ArduinoServiceUtils.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/permissions.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/pom.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/ArduinoManagerService.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/util/APIUtil.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/permissions.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/pom.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/constants/ArduinoConstants.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/exception/ArduinoDeviceMgtPluginException.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManager.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManagerService.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/ArduinoDAO.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/impl/ArduinoDeviceDAOImpl.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/feature/ArduinoFeatureManager.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/ArduinoUtils.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/DeviceSchemaInitializer.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/internal/ArduinoManagementServiceComponent.java create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/pom.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.hbs create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.js create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.json create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/public/images/ardunio-icon.png create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/public/images/thumb.png create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/ardunio-icon.png create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/myDevices_analytics.png create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/schematicsGuide.png create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/thumb.png create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/download.js create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/jquery.validate.js create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.hbs create mode 100644 components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.json create mode 100644 components/iot-plugins/arduino-plugin/pom.xml create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java create mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml create mode 100644 components/iot-plugins/camera-plugin/pom.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/pom.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/DigitalDisplayControllerService.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/dto/DeviceJSON.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/exception/DigitalDisplayException.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/model/ScreenShotModel.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/util/DigitalDisplayMQTTConnector.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/websocket/DigitalDisplayWebSocketServerEndPoint.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/pom.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/DigitalDisplayManagerService.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/util/APIUtil.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/permissions.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/pom.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/constants/DigitalDisplayConstants.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/exception/DigitalDisplayDeviceMgtPluginException.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManager.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManagerService.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/DigitalDisplayDAO.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/impl/DigitalDisplayDeviceDAOImpl.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/feature/DigitalDisplayFeatureManager.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DeviceSchemaInitializer.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DigitalDisplayUtils.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/internal/DigitalDisplayManagementServiceComponent.java create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/pom.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.hbs create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.js create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.json create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/default-screen.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/display-icon.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/thumb.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/js/websocket.js create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/display-icon.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/myDevices_analytics.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/add-resource.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/edit-sequence.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/get-content-list.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/get-device-status.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/remove-resource.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/restart-browser.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/restart-display.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/restart-server.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/screenshot.png create mode 100755 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/terminate-display.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/upload-content.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/schematicsGuide.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/thumb.png create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/download.js create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/jquery.validate.js create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.hbs create mode 100644 components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.json create mode 100644 components/iot-plugins/digital-display-plugin/pom.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/pom.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneControllerService.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneRealTimeService.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/exception/DroneAnalyzerException.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/transport/DroneAnalyzerXMPPConnector.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/trasformer/MessageTransformer.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/util/DroneAnalyzerServiceUtils.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/pom.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/DroneManagerService.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/util/APIUtil.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/pom.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/DroneConstants.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/MessageConfig.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/DroneController.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/impl/DroneControllerImpl.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/exception/DroneAnalyzerDeviceMgtPluginException.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManager.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManagerService.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/DroneAnalyzerDAO.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/impl/DroneAnalyzerDeviceDAOImpl.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/feature/DroneAnalyzerFeatureManager.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DeviceSchemaInitializer.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DroneAnalyzerUtils.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/internal/DroneAnalyzerManagementServiceComponent.java create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/pom.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.hbs create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.json create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/public/images/drone-icon.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/public/images/thumb.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/images/devices_analytics.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/images/drone-icon.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/images/schematicsGuide.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/images/thumb.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/download.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/jquery.validate.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.hbs create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.json create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/css/main-app.css create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/background_drone.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/direction_drone.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/pitch_drone.png create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/no_video_preview.gif create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/3dObjectControler.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/Coordinates.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/OrbitAndPanControls.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/three.min.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/ajax_handler.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/general_handler create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/websocket_api create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/config/config.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/d3.min.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/download.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/initJs create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jQueryRotate.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jquery.validate.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/mainHandler create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/controller.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/flight_dynamics.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/realtime_plotting create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.hbs create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.js create mode 100644 components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.json create mode 100644 components/iot-plugins/drone-analyzer-plugin/pom.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/pom.xml create mode 100755 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/log4j.properties create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DeviceUsageDTO.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/PolicyManagementService.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/util/ResponsePayload.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/permissions.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100755 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/pom.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/app-conf.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/public/js/validate-register.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/public/js/operation-bar.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/css/graph.css create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/images/map-marker-1.png create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/images/map-marker-2.png create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/d3.min.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/device-stats.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/moment.min.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/rickshaw.min.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/public/js/platform-configuration.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/css/codemirror.css create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/codemirror.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/policy-edit.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/sql.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/css/codemirror.css create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/codemirror.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/policy-view.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/sql.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/css/codemirror.css create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/codemirror.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/policy-create.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/sql.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.js create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.hbs create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.json create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/DeviceManagementConfigurationManager.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueue.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueuesConfig.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/DeviceManagementConfiguration.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ObjectFactory.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/mqtt/MqttConfig.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppAccount.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppConfig.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppServerClient.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/DeviceControllerException.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/IoTException.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/NotImplementedException.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/UnauthorizedException.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IoTCommonDataHolder.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IotDeviceManagementServiceComponent.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/mqtt/PolicyPush.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/DeviceRecord.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorDataManager.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorRecord.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/service/IoTServerStartupListener.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/CommunicationUtils.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandler.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandlerException.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportUtils.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/mqtt/MQTTTransportHandler.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/xmpp/XMPPTransportHandler.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IoTUtil.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IotDeviceManagementUtil.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipArchive.java create mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipUtil.java create mode 100644 components/iot-plugins/iot-base-plugin/pom.xml create mode 100644 components/iot-plugins/pom.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/build.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/pom.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/assembly/src.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/pom.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/RaspberryPiControllerService.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/DeviceData.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/SensorData.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/exception/RaspberrypiException.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/transport/RaspberryPiMQTTConnector.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/util/RaspberrypiServiceUtils.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/pom.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/RaspberryPiManagerService.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/util/APIUtil.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/pom.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/constants/RaspberrypiConstants.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/exception/RaspberrypiDeviceMgtPluginException.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManager.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManagerService.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/RaspberrypiDAO.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/impl/RaspberrypiDeviceDAOImpl.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/feature/RaspberrypiFeatureManager.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/DeviceSchemaInitializer.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/RaspberrypiUtils.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/internal/RaspberrypiManagementServiceComponent.java create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/pom.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.hbs create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.js create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.json create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/public/images/respberry-icon.png create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/public/images/thumb.png create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/myDevices_analytics.png create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/respberry-icon.png create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/schematicsGuide.png create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/thumb.png create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/download.js create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/jquery.validate.js create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.hbs create mode 100644 components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.json create mode 100644 components/iot-plugins/raspberrypi-plugin/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/Bootstrap.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/http/FireAlarmHTTPCommunicator.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/mqtt/FireAlarmMQTTCommunicator.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/xmpp/FireAlarmXMPPCommunicator.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConfiguration.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConstants.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentUtilOperations.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/enrollment/EnrollmentManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/exception/AgentCoreOperationException.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/sidhdhi/SidhdhiQuery.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/CommunicationUtils.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandlerException.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportUtils.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/http/HTTPTransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/mqtt/MQTTTransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/xmpp/XMPPTransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/VirtualHardwareManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/ui/AgentUI.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/alarm-off.gif create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/alarm-on.gif create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/cep_query.txt create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/deviceConfig.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/fireAlarmSound.mid create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/build.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/manifest.mf create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/build-impl.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/genfiles.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/bulb-on.jpg create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-off.gif create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-on.gif create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/fireAlarmSound.mid create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/build.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/bulb-on.jpg create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/build.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/assembly/src.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/VirtualFireAlarmControllerService.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/DeviceData.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/SensorData.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/exception/VirtualFireAlarmException.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmMQTTConnector.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmXMPPConnector.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/SecurityManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/VirtualFireAlarmServiceUtils.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/ContentType.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/SCEPOperation.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/VirtualFireAlarmManagerService.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/util/APIUtil.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/web.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/constants/VirtualFireAlarmConstants.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/exception/VirtualFirealarmDeviceMgtPluginException.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManagerService.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/VirtualFireAlarmDAO.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/impl/VirtualFireAlarmDeviceDAOImpl.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/feature/VirtualFirealarmFeatureManager.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/DeviceSchemaInitializer.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/VirtualFireAlarmUtils.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/internal/VirtualFirealarmManagementServiceComponent.java create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/pom.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/assembly/src.xml create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.hbs create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.js create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.json create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/public/images/firealarm-icon.png create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/public/images/thumb.png create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.policy-edit/policy-edit.hbs create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.policy-edit/policy-edit.json create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.policy-view/policy-view.hbs create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.policy-view/policy-view.json create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.policy-wizard/policy-wizard.hbs create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.policy-wizard/policy-wizard.json create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/firealarm-icon.png create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/myDevices_analytics.png create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/schematicsGuide.png create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/thumb.png create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/js/download.js create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/js/jquery.validate.js create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.hbs create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.json create mode 100644 components/iot-plugins/virtual-fire-alarm-plugin/pom.xml delete mode 100644 components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/pom.xml delete mode 100644 components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerUtil.java delete mode 100644 components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/OAuthTokenValidatorValve.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/ConfigurationMgtService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/DeviceManagementService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/EnrollmentService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/OperationMgtService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/PolicyMgtService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/AndroidOperation.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationInstallation.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationUninstallation.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/BlacklistApplications.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Camera.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/DeviceEncryption.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Disenrollment.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/LockCode.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Notification.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/PasscodePolicy.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WebClip.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Wifi.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WipeData.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationInstallationBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationUninstallationBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/BlacklistApplicationsBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/CameraBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/DisenrollmentBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/EncryptionBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/LockCodeBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/NotificationBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/PasswordPolicyBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WebClipBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WifiBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WipeDataBeanWrapper.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorHandler.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorMessage.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/GsonMessageBodyHandler.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidAgentException.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidOperationException.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/BadRequestException.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/OperationConfigurationException.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidAPIUtils.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidConstants.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/DeviceIDHolder.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/Message.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/permissions.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/web.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/servicelist.css create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/pom.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManager.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidFeatureManager.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPolicyMonitoringService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidDAOFactory.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidFeatureManagementDAOException.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidDeviceDAOImpl.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidFeatureDAOImpl.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMResult.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMService.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMUtil.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginConstants.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginUtils.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidUtils.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementDataHolder.java create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementServiceComponent.java create mode 100644 components/mobile-plugins/android-plugin/pom.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Authentication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceNotification.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/License.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Profile.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorHandler.java rename components/{key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/APIFaultException.java => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorMessage.java} (63%) create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/MDMAPIException.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/context/DeviceOperationContext.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAndroidOperationUtil.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAppConstants.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMIOSOperationUtil.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ApplicationWrapper.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileApp.java rename components/{key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerConstants.java => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileAppTypes.java} (69%) create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PolicyWrapper.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PriorityUpdatedPolicyWrapper.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/Profile.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ProfileFeature.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/RoleWrapper.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserCredentialWrapper.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/AppStoreApplication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/EnterpriseApplication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/WebApplication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/AppStoreApplication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/EnterpriseApplication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/RemoveApplication.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/WebClip.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/Constants.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/MDMUtil.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/SetReferenceTransformer.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/Application.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/GsonMessageBodyHandler.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/web.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/pom.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/assembly/src.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/js/operation-bar.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-ios.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/operations.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/public/js/platform-configuration.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/js/policy-create.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-android.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-ios.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-windows.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/js/policy-view.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-android.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-ios.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-windows.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/js/policy-create.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-android.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-ios.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-windows.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.js create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.json create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/pom.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-config.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-apis-config.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-ds-config.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/log4j.properties create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/sql/h2.sql create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testdbconfig.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testng.xml create mode 100644 components/mobile-plugins/mobile-base-plugin/pom.xml rename components/{key-mgt => mobile-plugins}/pom.xml (79%) create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/PluginConstants.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/SyncmlCommandType.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/CacheEntry.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/Token.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/WindowsPluginProperties.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/AuthenticationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/BadRequestException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/CertificateGenerationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/FileOperationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/KeyStoreGenerationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/MDMAPIException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlMessageFormatException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlOperationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WAPProvisioningException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsConfigurationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsDeviceEnrolmentException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsOperationsException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/AuthenticationInfo.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/BSTValidator.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ConfigInitializerContextListener.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceIDHolder.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceUtil.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorHandler.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorMessage.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/GsonMessageBodyHandler.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/Message.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/SOAPSecurityHandler.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/UsernameTokenValidator.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsAPIUtils.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsDeviceUtils.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AddTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Alert.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AtomicTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ChallengeTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Credential.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/DeleteTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ExecuteTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Get.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Item.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/MetaTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Replace.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Results.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SequenceTag.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Source.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Status.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlBody.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlDocument.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlHeader.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Target.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/WindowsOperationException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/Constants.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/DeviceInfo.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationCode.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationReply.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationUtils.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlCredentials.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlGenerator.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlParser.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/Operations.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Device.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Disenrollment.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationRequest.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationResponse.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/StorageEncryption.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/DisenrollmentBeanWrapper.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/EncryptBeanWrapper.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/impl/OperationsImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/util/OperationStore.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/BSTProvider.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/beans/Credentials.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/impl/BSTProviderImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/configurationmgtservice/ConfigurationMgtService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/devicemgtservice/DeviceManagementService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/DiscoveryService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryRequest.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryResponse.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/impl/DiscoveryServiceImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/policymgtservice/PolicyMgtService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/SyncmlService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/BasicOperation.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/PasscodePolicy.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Profile.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Wifi.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/impl/SyncmlServiceImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/PolicyManager.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/SyncmlUtils.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/CertificateEnrollmentService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/AdditionalContext.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/BinarySecurityToken.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/ContextItem.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityToken.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityTokenResponse.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestedSecurityToken.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/impl/CertificateEnrollmentServiceImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/CertificateSigningService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/KeyStoreGenerator.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/MessageHandler.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/CertificateEnrollmentPolicyService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Attributes.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CA.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CACollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAReferenceCollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURI.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURICollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateEnrollmentPolicy.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateValidity.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Client.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CryptoProviders.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/EnrollmentPermission.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Extension.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ExtensionCollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/FilterOIDCollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPolicies.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPoliciesResponse.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/KeyArchivalAttributes.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OID.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDCollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDReferenceCollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ObjectFactory.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PolicyCollection.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PrivateKeyAttributes.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RARequirements.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RequestFilter.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Response.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Revision.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/SupersededPolicies.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/impl/CertificateEnrollmentPolicyServiceImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wso2mdm.jks create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/web.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/servicelist.css create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/pom.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManager.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsFeatureManager.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsPolicyMonitoringService.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsDAOFactory.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsFeatureManagementDAOException.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsDeviceDAOImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsFeatureDAOImpl.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginConstants.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginUtils.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsUtils.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementDataHolder.java create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementServiceComponent.java create mode 100644 components/mobile-plugins/windows-plugin/pom.xml diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/build.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/build.xml new file mode 100644 index 000000000..b0b52fc6b --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/build.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/pom.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/pom.xml new file mode 100644 index 000000000..a3a622fc4 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/pom.xml @@ -0,0 +1,90 @@ + + + + + + androidsense-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.androidsense.analytics + WSO2 Carbon - IoT Server Android Sense Analytics capp + pom + + + + + maven-clean-plugin + 2.4.1 + + + auto-clean + initialize + + clean + + + + + + maven-antrun-plugin + 1.7 + + + process-resources + + + + + + + run + + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/assembly/src.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/assembly/src.xml new file mode 100644 index 000000000..a5a375010 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.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/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/EventReceiver_accelerometer.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/EventReceiver_accelerometer.xml new file mode 100644 index 000000000..cf95025b6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/EventReceiver_accelerometer.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/artifact.xml new file mode 100644 index 000000000..aeead5417 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventreceiver_accelerometer_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_accelerometer.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/artifact.xml new file mode 100644 index 000000000..cc7c49907 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_accelerometer.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/org_wso2_iot_devices_accelerometer.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/org_wso2_iot_devices_accelerometer.xml new file mode 100644 index 000000000..5e2d427c4 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstore_accelerometer_1.0.0/org_wso2_iot_devices_accelerometer.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.accelerometer: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 + + + accelerometer + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/artifact.xml new file mode 100644 index 000000000..4a9d840f9 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.accelerometer_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/org.wso2.iot.devices.accelerometer_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/org.wso2.iot.devices.accelerometer_1.0.0.json new file mode 100644 index 000000000..db6af8eec --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Eventstream_accelerometer_1.0.0/org.wso2.iot.devices.accelerometer_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.accelerometer", + "version": "1.0.0", + "nickName": "accelerometer Data", + "description": "accelerometer data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "accelerometer","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/Accelerometer_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/Accelerometer_Sensor_Script.xml new file mode 100644 index 000000000..e1533c75c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/Accelerometer_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + Accelerometer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..3cdac3edd --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + Accelerometer_Sensor_Script.xml + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/artifacts.xml new file mode 100644 index 000000000..bc58f6a36 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Accelerometer/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/EventReceiver_battery.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/EventReceiver_battery.xml new file mode 100644 index 000000000..af55acea8 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/EventReceiver_battery.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/artifact.xml new file mode 100644 index 000000000..3b963dafc --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventreceiver_battery_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_battery.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/artifact.xml new file mode 100644 index 000000000..6bc9aadd8 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_battery.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/org_wso2_iot_devices_battery.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/org_wso2_iot_devices_battery.xml new file mode 100644 index 000000000..ce70882da --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstore_battery_1.0.0/org_wso2_iot_devices_battery.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.battery: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 + + + battery + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/artifact.xml new file mode 100644 index 000000000..a03e58d40 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.battery_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/org.wso2.iot.devices.battery_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/org.wso2.iot.devices.battery_1.0.0.json new file mode 100644 index 000000000..c0a2106f0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Eventstream_battery_1.0.0/org.wso2.iot.devices.battery_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.battery", + "version": "1.0.0", + "nickName": "battery Data", + "description": "battery data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "battery","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/Battery_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/Battery_Sensor_Script.xml new file mode 100644 index 000000000..07559e342 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/Battery_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + Battery_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..b573355bb --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Battery_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/artifacts.xml new file mode 100644 index 000000000..2b72bb5b9 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Battery/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/EventReceiver_gps.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/EventReceiver_gps.xml new file mode 100644 index 000000000..dd51b2817 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/EventReceiver_gps.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/artifact.xml new file mode 100644 index 000000000..4ae981667 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventreceiver_gps_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_gps.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/artifact.xml new file mode 100644 index 000000000..1ad7609e6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_gps.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/org_wso2_iot_devices_gps.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/org_wso2_iot_devices_gps.xml new file mode 100644 index 000000000..781c37ab0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstore_gps_1.0.0/org_wso2_iot_devices_gps.xml @@ -0,0 +1,69 @@ + + + + + + org.wso2.iot.devices.gps: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 + + + latitude + false + false + false + FLOAT + + + longitude + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/artifact.xml new file mode 100644 index 000000000..2028042e0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.gps_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/org.wso2.iot.devices.gps_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/org.wso2.iot.devices.gps_1.0.0.json new file mode 100644 index 000000000..04d2b1069 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Eventstream_gps_1.0.0/org.wso2.iot.devices.gps_1.0.0.json @@ -0,0 +1,23 @@ +{ + "name": "org.wso2.iot.devices.gps", + "version": "1.0.0", + "nickName": "GPS Data", + "description": "GPS data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "latitude","type": "FLOAT" + }, + { + "name": "longitude","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/GPS_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/GPS_Sensor_Script.xml new file mode 100644 index 000000000..e9f0b83a7 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/GPS_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..87dcbba09 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + GPS_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/artifacts.xml new file mode 100644 index 000000000..750796e82 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/GPS/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/EventReceiver_gravity.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/EventReceiver_gravity.xml new file mode 100644 index 000000000..a1d23503a --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/EventReceiver_gravity.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/artifact.xml new file mode 100644 index 000000000..00108bb4e --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventreceiver_gravaity_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_gravity.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/artifact.xml new file mode 100644 index 000000000..0abc61558 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_gravity.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/org_wso2_iot_devices_gravity.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/org_wso2_iot_devices_gravity.xml new file mode 100644 index 000000000..2c68c0d43 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstore_gravity_1.0.0/org_wso2_iot_devices_gravity.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.gravity: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 + + + gravity + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/artifact.xml new file mode 100644 index 000000000..7d6e0d5f6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.gravity_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/org.wso2.iot.devices.gravity_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/org.wso2.iot.devices.gravity_1.0.0.json new file mode 100644 index 000000000..f18bd87be --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Eventstream_gravity_1.0.0/org.wso2.iot.devices.gravity_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.gravity", + "version": "1.0.0", + "nickName": "Gravity Data", + "description": "Gravity data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "gravity","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/Gravity_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/Gravity_Sensor_Script.xml new file mode 100644 index 000000000..13fd7222d --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/Gravity_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..4459a44fe --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Gravity_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/artifacts.xml new file mode 100644 index 000000000..7fc9acb07 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gravity/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/EventReceiver_gyroscope.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/EventReceiver_gyroscope.xml new file mode 100644 index 000000000..00c7092ba --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/EventReceiver_gyroscope.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/artifact.xml new file mode 100644 index 000000000..1ce90879c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventreceiver_gyroscope_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_gyroscope.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/artifact.xml new file mode 100644 index 000000000..6a2662c04 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_gyroscope.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/org_wso2_iot_devices_gyroscope.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/org_wso2_iot_devices_gyroscope.xml new file mode 100644 index 000000000..899e32c85 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstore_gyroscope_1.0.0/org_wso2_iot_devices_gyroscope.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.gyroscope: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 + + + gyroscope + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/artifact.xml new file mode 100644 index 000000000..f221d409c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.gyroscope_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/org.wso2.iot.devices.gyroscope_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/org.wso2.iot.devices.gyroscope_1.0.0.json new file mode 100644 index 000000000..0583da295 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Eventstream_gyroscope_1.0.0/org.wso2.iot.devices.gyroscope_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.gyroscope", + "version": "1.0.0", + "nickName": "Gyroscope Data", + "description": "Gyroscope data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "gyroscope","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/Gyroscope_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/Gyroscope_Sensor_Script.xml new file mode 100644 index 000000000..88e20226b --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/Gyroscope_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..de967666d --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Gyroscope_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/artifacts.xml new file mode 100644 index 000000000..928f9398e --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Gyroscope/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/EventReceiver_light.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/EventReceiver_light.xml new file mode 100644 index 000000000..09ced9de4 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/EventReceiver_light.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/artifact.xml new file mode 100644 index 000000000..604e9384e --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventreceiver_light_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_light.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/artifact.xml new file mode 100644 index 000000000..1e06aaa29 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_light.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/org_wso2_iot_devices_light.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/org_wso2_iot_devices_light.xml new file mode 100644 index 000000000..d7051c715 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstore_light_1.0.0/org_wso2_iot_devices_light.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.light: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 + + + light + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/artifact.xml new file mode 100644 index 000000000..6a6db53ad --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.light_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/org.wso2.iot.devices.light_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/org.wso2.iot.devices.light_1.0.0.json new file mode 100644 index 000000000..253f0b0c0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Eventstream_light_1.0.0/org.wso2.iot.devices.light_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.light", + "version": "1.0.0", + "nickName": "light Data", + "description": "light data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "light","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/Light_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/Light_Sensor_Script.xml new file mode 100644 index 000000000..53b53d544 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/Light_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + Light_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..817faf53c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Light_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/artifacts.xml new file mode 100644 index 000000000..1138a4c60 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Light/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/EventReceiver_magnetic.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/EventReceiver_magnetic.xml new file mode 100644 index 000000000..33b0ee1ac --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/EventReceiver_magnetic.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/artifact.xml new file mode 100644 index 000000000..4a9272db8 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventreceiver_magnetic_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_magnetic.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/artifact.xml new file mode 100644 index 000000000..67a726ea6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_magnetic.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/org_wso2_iot_devices_magnetic.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/org_wso2_iot_devices_magnetic.xml new file mode 100644 index 000000000..725e2103f --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstore_magnetic_1.0.0/org_wso2_iot_devices_magnetic.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.magnetic: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 + + + magnetic + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/artifact.xml new file mode 100644 index 000000000..24b52cb62 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.magnetic_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/org.wso2.iot.devices.magnetic_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/org.wso2.iot.devices.magnetic_1.0.0.json new file mode 100644 index 000000000..5cbe22ba1 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Eventstream_magnetic_1.0.0/org.wso2.iot.devices.magnetic_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.magnetic", + "version": "1.0.0", + "nickName": "magnetic Data", + "description": "magnetic data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "magnetic","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/Magnetic_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/Magnetic_Sensor_Script.xml new file mode 100644 index 000000000..3ee9b5797 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/Magnetic_Sensor_Script.xml @@ -0,0 +1,30 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..0c88076bf --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Magnetic_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/artifacts.xml new file mode 100644 index 000000000..b98adc8cf --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Magnetic/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/EventReceiver_pressure.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/EventReceiver_pressure.xml new file mode 100644 index 000000000..e23884d78 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/EventReceiver_pressure.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/artifact.xml new file mode 100644 index 000000000..3f6e571d3 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventreceiver_pressure_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_pressure.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/artifact.xml new file mode 100644 index 000000000..139505cfc --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_pressure.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/org_wso2_iot_devices_pressure.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/org_wso2_iot_devices_pressure.xml new file mode 100644 index 000000000..5e2f91f34 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstore_pressure_1.0.0/org_wso2_iot_devices_pressure.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.pressure: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 + + + pressure + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/artifact.xml new file mode 100644 index 000000000..9c5d908c2 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.pressure_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/org.wso2.iot.devices.pressure_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/org.wso2.iot.devices.pressure_1.0.0.json new file mode 100644 index 000000000..f58059d28 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Eventstream_pressure_1.0.0/org.wso2.iot.devices.pressure_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.pressure", + "version": "1.0.0", + "nickName": "Pressure Data", + "description": "Pressure data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "pressure","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/Pressure_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/Pressure_Sensor_Script.xml new file mode 100644 index 000000000..8d731ca31 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/Pressure_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..4ff8b5331 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Pressure_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/artifacts.xml new file mode 100644 index 000000000..7403d3a69 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Pressure/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/EventReceiver_proximity.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/EventReceiver_proximity.xml new file mode 100644 index 000000000..a5024f7d7 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/EventReceiver_proximity.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/artifact.xml new file mode 100644 index 000000000..a6c67ff6c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventreceiver_proximity_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_proximity.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/artifact.xml new file mode 100644 index 000000000..0d21663c7 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_proximity.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/org_wso2_iot_devices_proximity.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/org_wso2_iot_devices_proximity.xml new file mode 100644 index 000000000..ef4819322 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstore_proximity_1.0.0/org_wso2_iot_devices_proximity.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.proximity: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 + + + proximity + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/artifact.xml new file mode 100644 index 000000000..4458b50a9 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.proximity_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/org.wso2.iot.devices.proximity_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/org.wso2.iot.devices.proximity_1.0.0.json new file mode 100644 index 000000000..88fb90089 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Eventstream_proximity_1.0.0/org.wso2.iot.devices.proximity_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.proximity", + "version": "1.0.0", + "nickName": "Proximity Data", + "description": "Proximity data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "proximity","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/Proximity_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/Proximity_Sensor_Script.xml new file mode 100644 index 000000000..4bdbcc212 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/Proximity_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..8486e84ee --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Proximity_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/artifacts.xml new file mode 100644 index 000000000..8b24e448e --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Proximity/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/EventReceiver_rotation.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/EventReceiver_rotation.xml new file mode 100644 index 000000000..a2bb72edd --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/EventReceiver_rotation.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/artifact.xml new file mode 100644 index 000000000..d49ec80d5 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventreceiver_rotation_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_rotation.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/artifact.xml new file mode 100644 index 000000000..816c8f58c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_rotation.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/org_wso2_iot_devices_rotation.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/org_wso2_iot_devices_rotation.xml new file mode 100644 index 000000000..941f62198 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstore_rotation_1.0.0/org_wso2_iot_devices_rotation.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.rotation: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 + + + rotation + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/artifact.xml new file mode 100644 index 000000000..585d53afb --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.rotation_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/org.wso2.iot.devices.rotation_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/org.wso2.iot.devices.rotation_1.0.0.json new file mode 100644 index 000000000..03881bcf3 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Eventstream_rotation_1.0.0/org.wso2.iot.devices.rotation_1.0.0.json @@ -0,0 +1,20 @@ +{ + "name": "org.wso2.iot.devices.rotation", + "version": "1.0.0", + "nickName": "Rotation Data", + "description": "Rotation data received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + { + "name": "rotation","type": "FLOAT" + } + ] +} + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/Rotation_Sensor_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/Rotation_Sensor_Script.xml new file mode 100644 index 000000000..e03e7fab5 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/Rotation_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..9a959892d --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Rotation_Sensor_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/artifacts.xml new file mode 100644 index 000000000..7bbe4ac50 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/Rotation/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/EventReceiver_wordcount.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/EventReceiver_wordcount.xml new file mode 100644 index 000000000..dac705e76 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/EventReceiver_wordcount.xml @@ -0,0 +1,27 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/artifact.xml new file mode 100644 index 000000000..b9ee00adb --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventreceiver_wordcount_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_wordcount.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/artifact.xml new file mode 100644 index 000000000..f1ff8a5b8 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_wordcount.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/org_wso2_iot_devices_wordcount.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/org_wso2_iot_devices_wordcount.xml new file mode 100644 index 000000000..8e9649dd1 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstore_wordcount_1.0.0/org_wso2_iot_devices_wordcount.xml @@ -0,0 +1,76 @@ + + + + + + org.wso2.iot.devices.wordcount: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 + + + sessionId + false + false + false + STRING + + + word + false + false + false + STRING + + + status + false + false + false + STRING + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/artifact.xml new file mode 100644 index 000000000..c3cc85f26 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.wordcount_1.0.0.json + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/org.wso2.iot.devices.wordcount_1.0.0.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/org.wso2.iot.devices.wordcount_1.0.0.json new file mode 100644 index 000000000..c5e6e7748 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Eventstream_wordcount_1.0.0/org.wso2.iot.devices.wordcount_1.0.0.json @@ -0,0 +1,17 @@ +{ + "name": "org.wso2.iot.devices.wordcount", + "version": "1.0.0", + "nickName": "Word Count Data", + "description": "Word Count received from the Device", + "metaData": [ + {"name":"owner","type":"STRING"}, + {"name":"deviceType","type":"STRING"}, + {"name":"deviceId","type":"STRING"}, + {"name":"time","type":"LONG"} + ], + "payloadData": [ + {"name" : "sessionId", "type" : "STRING"}, + {"name" : "word", "type" : "STRING"}, + {"name" : "status", "type" : "STRING"} + ] +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/Wordcount_Script.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/Wordcount_Script.xml new file mode 100644 index 000000000..9050af8ba --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/Wordcount_Script.xml @@ -0,0 +1,34 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..4f9088a72 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Wordcount_Script.xml + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/artifacts.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/artifacts.xml new file mode 100644 index 000000000..737b58626 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.analytics/src/main/resources/carbonapps/WordCount/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/pom.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/pom.xml new file mode 100644 index 000000000..4b2b5e682 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/pom.xml @@ -0,0 +1,205 @@ + + + + androidsense-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.androidsense.controller.api + war + WSO2 Carbon - Android Sense Controller API + WSO2 Carbon - Android Sense Service Controller API Implementation + http://wso2.org + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.androidsense.plugin + provided + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + provided + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + android_sense + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/AndroidSenseControllerService.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/AndroidSenseControllerService.java new file mode 100644 index 000000000..5d740dc33 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/AndroidSenseControllerService.java @@ -0,0 +1,667 @@ +/* + * 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.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.common.AnalyticsDataRecord; +import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException; +import org.wso2.carbon.device.mgt.analytics.exception.DeviceManagementAnalyticsException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature; +import org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.transport.AndroidSenseMQTTConnector; +import org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.util.DeviceData; +import org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.util.SensorData; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; +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 org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +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.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.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * The api for + */ +@DeviceType(value = "android_sense") +@API(name = "android_sense", version = "1.0.0", context = "/android_sense", tags = {"android_sense"}) +public class AndroidSenseControllerService { + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private static Log log = LogFactory.getLog(AndroidSenseControllerService.class); + private static AndroidSenseMQTTConnector androidSenseMQTTConnector; + + /** + * Fetches the `AndroidSenseMQTTConnector` specific to this Android Sense controller service. + * + * @return the 'AndroidSenseMQTTConnector' instance bound to the 'AndroidSenseMQTTConnector' variable of + * this service. + */ + @SuppressWarnings("Unused") + public AndroidSenseMQTTConnector getAndroidSenseMQTTConnector() { + return androidSenseMQTTConnector; + } + + /** + * Sets the `AndroidSenseMQTTConnector` variable of this Android Sense controller service. + * + * @param androidSenseMQTTConnector a 'AndroidSenseMQTTConnector' object that handles all MQTT related + * communications of any connected Android Sense device-type + */ + @SuppressWarnings("Unused") + public void setAndroidSenseMQTTConnector(final AndroidSenseMQTTConnector androidSenseMQTTConnector) { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + AndroidSenseControllerService.androidSenseMQTTConnector = androidSenseMQTTConnector; + if (MqttConfig.getInstance().isEnabled()) { + androidSenseMQTTConnector.connect(); + } else { + log.warn("MQTT disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmMQTTConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + private boolean waitForServerStartup() { + while (!IoTServerStartupListener.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + /** + * Service to push all the sensor data collected by the Android. Called by the Android device + * + * @param dataMsg The json string containing sensor readings + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API + */ + @Path("controller/sensors") + @POST + @Consumes(MediaType.APPLICATION_JSON) + public void addSensorData(DeviceData dataMsg, @Context HttpServletResponse response) { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + SensorData[] sensorData = dataMsg.values; + String streamDef = null; + Object payloadData[] = null; + String sensorName = null; + for (SensorData sensor : sensorData) { + switch (sensor.key) { + case "battery" : + streamDef = AndroidSenseConstants.BATTERY_STREAM_DEFINITION; + payloadData = new Float[]{Float.parseFloat(sensor.value)}; + sensorName = AndroidSenseConstants.SENSOR_BATTERY; + break; + case "GPS" : + streamDef = AndroidSenseConstants.GPS_STREAM_DEFINITION; + String gpsValue = sensor.value; + String gpsValuesString[] = gpsValue.split(","); + Float gpsValues[] = new Float[2]; + gpsValues[0] = Float.parseFloat(gpsValuesString[0]); + gpsValues[1] = Float.parseFloat(gpsValuesString[0]); + payloadData = gpsValues; + sensorName = AndroidSenseConstants.SENSOR_GPS; + break; + default : + try { + int androidSensorId = Integer.parseInt(sensor.key); + String value = sensor.value; + String sensorValueString[] = value.split(","); + Float sensorValues[] = new Float[1]; + switch (androidSensorId) { + case 1: + streamDef = AndroidSenseConstants.ACCELEROMETER_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValueString[0]) * + Float.parseFloat(sensorValueString[0]) * Float.parseFloat(sensorValueString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_ACCELEROMETER; + break; + case 2: + streamDef = AndroidSenseConstants.MAGNETIC_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValueString[0]) * + Float.parseFloat(sensorValueString[0]) * Float.parseFloat(sensorValueString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_MAGNETIC; + break; + case 4: + streamDef = AndroidSenseConstants.GYROSCOPE_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValueString[0]) * + Float.parseFloat(sensorValueString[0]) * Float.parseFloat(sensorValueString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_GYROSCOPE; + break; + case 5: + streamDef = AndroidSenseConstants.LIGHT_STREAM_DEFINITION; + sensorName = AndroidSenseConstants.SENSOR_LIGHT; + payloadData = new Float[]{Float.parseFloat(sensorValueString[0])}; + break; + case 6: + streamDef = AndroidSenseConstants.PRESSURE_STREAM_DEFINITION; + sensorName = AndroidSenseConstants.SENSOR_PRESSURE; + payloadData = new Float[]{Float.parseFloat(sensorValueString[0])}; + break; + case 8: + streamDef = AndroidSenseConstants.PROXIMITY_STREAM_DEFINITION; + sensorName = AndroidSenseConstants.SENSOR_PROXIMITY; + payloadData = new Float[]{Float.parseFloat(sensorValueString[0])}; + break; + case 9: + streamDef = AndroidSenseConstants.GRAVITY_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValueString[0]) * + Float.parseFloat(sensorValueString[0]) * Float.parseFloat(sensorValueString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_GRAVITY; + break; + case 11: + streamDef = AndroidSenseConstants.ROTATION_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValueString[0]) * + Float.parseFloat(sensorValueString[0]) * Float.parseFloat(sensorValueString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_ROTATION; + break; + } + } catch (NumberFormatException e) { + log.error("Invalid sensor value is sent from the device"); + continue; + } + } + Object metaData[] = {dataMsg.owner, AndroidSenseConstants.DEVICE_TYPE, dataMsg.deviceId, sensor.time}; + if (streamDef != null && payloadData != null && payloadData.length > 0) { + try { + SensorDataManager.getInstance() + .setSensorRecord(dataMsg.deviceId, sensorName, sensor.value, sensor.time); + deviceAnalyticsService.publishEvent(streamDef, "1.0.0", metaData, new Object[0], payloadData); + } catch (DataPublisherConfigurationException e) { + response.setStatus(Response.Status.UNSUPPORTED_MEDIA_TYPE.getStatusCode()); + } + } + } + } + + + /** + * End point which is called by Front-end js to get Light sensor readings from the server. + * + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/light") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "light", name = "Light", description = "Read Light data from the device", type = "monitor") + public SensorRecord getLightData(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_LIGHT); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Battery data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/battery") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "battery", name = "Battery", description = "Read Battery data from the device", type = "monitor") + public SensorRecord getBattery(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_BATTERY); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get GPS data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/gps") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "gps", name = "gps", description = "Read GPS data from the device", type = "monitor") + public SensorRecord getGPS(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_GPS); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Magnetic data readings from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/magnetic") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "magnetic", name = "Magnetic", description = "Read Magnetic data from the device", type = "monitor") + public SensorRecord readMagnetic(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, AndroidSenseConstants.SENSOR_MAGNETIC); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Accelerometer data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/accelerometer") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "accelerometer", name = "Accelerometer", description = "Read Accelerometer data from the device", + type = "monitor") + public SensorRecord readAccelerometer(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_ACCELEROMETER); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Rotation data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/rotation") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "rotation", name = "Rotation", description = "Read Rotational Vector data from the device", + type = "monitor") + public SensorRecord readRotation(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_ROTATION); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Proximity data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/proximity") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "proximity", name = "Proximity", description = "Read Proximity data from the device", + type = "monitor") + public SensorRecord readProximity(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_PROXIMITY); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Gyroscope data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/gyroscope") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "gyroscope", name = "Gyroscope", description = "Read Gyroscope data from the device", + type = "monitor") + public SensorRecord readGyroscope(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_GYROSCOPE); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Pressure data from the server. + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/pressure") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "pressure", name = "Pressure", description = "Read Pressure data from the device", type = "monitor") + public SensorRecord readPressure(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_PRESSURE); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point which is called by Front-end js to get Gravity data from the server. + * + * @param deviceId The registered device id + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API. + * @return This method returns a SensorRecord object. + */ + @Path("controller/device/{deviceId}/sensors/gravity") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "gravity", name = "Gravity", + description = "Read Gravity data from the device", type = "monitor") + public SensorRecord readGravity(@PathParam("deviceId") String deviceId, @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_GRAVITY); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + @Path("controller/device/{deviceId}/sensors/words") + @GET + @Consumes("application/json") + @Produces("application/json") + @Feature(code = "words", name = "Words", description = "Get the key words and occurrences", + type = "monitor") + public SensorRecord getWords(@PathParam("deviceId") String deviceId, @QueryParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + AndroidSenseConstants.SENSOR_WORDCOUNT); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return sensorRecord; + } + + /** + * End point to send the key words to the device + + * @param deviceId The registered device Id. + * @param keywords The key words to be sent. (Comma separated values) + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API + */ + @Path("controller/device/{deviceId}/sensors/words") + @POST + @Feature(code = "keywords", name = "Add Keywords", description = "Send keywords to the device", + type = "operation") + public void sendKeyWords(@PathParam("deviceId") String deviceId, @FormParam("keywords") String keywords, + @Context HttpServletResponse response) { + try { + String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + androidSenseMQTTConnector.publishDeviceData(username, deviceId, "add", keywords); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (TransportHandlerException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } + } + + /** + * End point to send the key words to the device + * + * @param deviceId The registered device Id. + * @param threshold The key words to be sent. (Comma separated values) + * @param response the HTTP servlet response object received by default as part of the HTTP + * call to this API + */ + @Path("controller/device/{deviceId}/sensors/words/threshold") + @POST + @Feature(code = "threshold", name = "Add a Threshold", description = "Set a threshold for word in the device", + type = "operation") + public void sendThreshold(@PathParam("deviceId") String deviceId, @FormParam("threshold") String threshold, + @Context HttpServletResponse response) { + try { + String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + androidSenseMQTTConnector.publishDeviceData(username, deviceId, "threshold", threshold); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (TransportHandlerException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } + } + + @Path("controller/device/{deviceId}/sensors/words") + @DELETE + @Feature(code = "remove", name = "Remove Keywords", description = "Remove the keywords", + type = "operation") + public void removeKeyWords(@PathParam("deviceId") String deviceId, @QueryParam("words") String words, + @Context HttpServletResponse response) { + try { + String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + androidSenseMQTTConnector.publishDeviceData(username, deviceId, "remove", words); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (TransportHandlerException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } + } + + /** + * Retrieve Sensor data for the device type + * + */ + @Path("controller/stats/device/{deviceId}/sensors/{sensorName}") + @GET + @Consumes("application/json") + @Produces("application/json") + public SensorData[] getAndroidSenseDeviceStats(@PathParam("deviceId") String deviceId, + @PathParam("sensorName") String sensor, + @QueryParam("from") long from, + @QueryParam("to") long to) { + String fromDate = String.valueOf(from); + String toDate = String.valueOf(to); + String user = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + List sensorDatas = new ArrayList<>(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + + AndroidSenseConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; + if (sensor.equals(AndroidSenseConstants.SENSOR_WORDCOUNT)) { + query = "owner:" + user + " AND deviceId:" + deviceId; + } + String sensorTableName = getSensorEventTableName(sensor); + try { + List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); + if (sensor.equals(AndroidSenseConstants.SENSOR_WORDCOUNT)) { + for (AnalyticsDataRecord record : records) { + SensorData sensorData = new SensorData(); + sensorData.setKey((String)record.getValue("word")); + sensorData.setTime((long) record.getValue("occurence")); + sensorData.setValue((String) record.getValue("sessionId")); + sensorDatas.add(sensorData); + } + } else { + Collections.sort(records, new Comparator() { + @Override + public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { + long t1 = (Long) o1.getValue("time"); + long t2 = (Long) o2.getValue("time"); + if (t1 < t2) { + return -1; + } else if (t1 > t2) { + return 1; + } else { + return 0; + } + } + }); + for (AnalyticsDataRecord record : records) { + SensorData sensorData = new SensorData(); + sensorData.setTime((long) record.getValue("time")); + sensorData.setValue("" + (float) record.getValue(sensor)); + sensorDatas.add(sensorData); + } + } + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } catch (DeviceManagementAnalyticsException e) { + String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; + log.error(errorMsg); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } + } + + /** + * get the event table from the sensor name. + */ + private String getSensorEventTableName(String sensorName) { + String sensorEventTableName; + switch (sensorName) { + case AndroidSenseConstants.SENSOR_ACCELEROMETER: + sensorEventTableName = "DEVICE_ACCELEROMETER_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_BATTERY: + sensorEventTableName = "DEVICE_BATTERY_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_GPS: + sensorEventTableName = "DEVICE_GPS_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_GRAVITY: + sensorEventTableName = "DEVICE_GRAVITY_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_GYROSCOPE: + sensorEventTableName = "DEVICE_GYROSCOPE_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_LIGHT: + sensorEventTableName = "DEVICE_LIGHT_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_MAGNETIC: + sensorEventTableName = "DEVICE_MAGNETIC_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_PRESSURE: + sensorEventTableName = "DEVICE_PRESSURE_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_PROXIMITY: + sensorEventTableName = "DevicePROXIMITYSummaryData"; + break; + case AndroidSenseConstants.SENSOR_ROTATION: + sensorEventTableName = "DEVICE_ROTATION_SUMMARY"; + break; + case AndroidSenseConstants.SENSOR_WORDCOUNT: + sensorEventTableName = "WORD_COUNT_SUMMARY"; + break; + default: + sensorEventTableName = ""; + } + return sensorEventTableName; + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/transport/AndroidSenseMQTTConnector.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/transport/AndroidSenseMQTTConnector.java new file mode 100644 index 000000000..52ace2bf5 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/transport/AndroidSenseMQTTConnector.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.transport; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +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.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +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.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.util.DeviceData; +import org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.util.SensorData; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +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 org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +@SuppressWarnings("no JAX-WS annotation") +public class AndroidSenseMQTTConnector extends MQTTTransportHandler { + private static Log log = LogFactory.getLog(AndroidSenseMQTTConnector.class); + private static String subscribeTopic = AndroidSenseConstants.MQTT_SUBSCRIBE_WORDS_TOPIC; + private static String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5); + + private AndroidSenseMQTTConnector() { + super(iotServerSubscriber, AndroidSenseConstants.DEVICE_TYPE, + MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic); + } + + @Override + public void connect() { + Runnable connector = new Runnable() { + public void run() { + while (!isConnected()) { + try { + connectToQueue(); + subscribeToQueue(); + } catch (TransportHandlerException e) { + log.warn("Connection/Subscription to MQTT Broker at: " + mqttBrokerEndPoint + " failed"); + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException ex) { + log.error("MQTT-Subscriber: Thread Sleep Interrupt Exception.", ex); + } + } + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + /** + * @throws TransportHandlerException in the event of any exceptions that occur whilst processing the message. + */ + @Override + public void processIncomingMessage() throws TransportHandlerException { + } + + /** + * @param message the message (of the type specific to the protocol) received from the device. + * @throws TransportHandlerException + */ + @Override + public void processIncomingMessage(MqttMessage message) throws TransportHandlerException { + } + + + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + if (publishData.length != 3) { + String errorMsg = "Incorrect number of arguments received to SEND-MQTT Message. " + + "Need to be [owner, deviceId, content]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg); + } + String deviceId = publishData[0]; + String operation = publishData[1]; + String resource = publishData[2]; + MqttMessage pushMessage = new MqttMessage(); + String publishTopic = "wso2/" + AndroidSenseConstants.DEVICE_TYPE + "/" + deviceId + "/command"; + if (operation.equals("add")) { + publishTopic = publishTopic + "/words"; + } else if (operation.equals("remove")) { + publishTopic = publishTopic + "/remove"; + } else if (operation.equals("threshold")) { + publishTopic = publishTopic + "/threshold"; + } else { + return; + } + String actualMessage = resource; + pushMessage.setPayload(actualMessage.getBytes(StandardCharsets.UTF_8)); + pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE); + pushMessage.setRetained(false); + publishToQueue(publishTopic, pushMessage); + } + + @Override + public void processIncomingMessage(MqttMessage mqttMessage, String... strings) throws TransportHandlerException { + String[] topic = strings[0].split("/"); + String deviceId = topic[3]; + if (log.isDebugEnabled()) { + log.debug("Received MQTT message for: & [DEVICE.ID-" + deviceId + "]"); + } + try { + Gson gson = new Gson(); + String actualMessage = mqttMessage.toString(); + DeviceData deviceData = gson.fromJson(actualMessage, DeviceData.class); + + SensorData[] sensorData = deviceData.values; + String streamDef = null; + Object payloadData[] = null; + String sensorName = null; + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain("carbon.super", true); + for (SensorData sensor : sensorData) { + if (sensor.key.equals("battery")) { + streamDef = AndroidSenseConstants.BATTERY_STREAM_DEFINITION; + payloadData = new Float[]{Float.parseFloat(sensor.value)}; + sensorName = AndroidSenseConstants.SENSOR_BATTERY; + } else if (sensor.key.equals("GPS")) { + streamDef = AndroidSenseConstants.GPS_STREAM_DEFINITION; + String gpsValue = sensor.value; + String gpsValuesString[] = gpsValue.split(","); + Float gpsValues[] = new Float[2]; + gpsValues[0] = Float.parseFloat(gpsValuesString[0]); + gpsValues[1] = Float.parseFloat(gpsValuesString[0]); + payloadData = gpsValues; + sensorName = AndroidSenseConstants.SENSOR_GPS; + } else if (sensor.key.equals("word")) { + try { + streamDef = AndroidSenseConstants.WORD_COUNT_STREAM_DEFINITION; + String[] values = sensor.value.split(","); + String sessionId = values[0]; + String keyword = values[1]; + int occurrence = Integer.parseInt(values[2]); + String status = values[3]; + sensorName = AndroidSenseConstants.SENSOR_WORDCOUNT; + + if (occurrence > 0) { + payloadData = new Object[]{sessionId, keyword, status}; + for (int i = 0; i < occurrence; i++) { + Long timestamp = Long.parseLong(values[3 + occurrence]); + publishDataToDAS(deviceId, timestamp, sensorName, streamDef, + sensor.value, payloadData); + + } + continue; + } + } catch (ArrayIndexOutOfBoundsException e) { + log.error( + "Timestamp does not match the occurence sensor values are sent from the device."); + } + continue; + } else { + try { + int androidSensorId = Integer.parseInt(sensor.key); + String sensorValue = sensor.value; + String sensorValuesString[] = sensorValue.split(","); + Float sensorValues[] = new Float[1]; + + switch (androidSensorId) { + case 1: + streamDef = AndroidSenseConstants.ACCELEROMETER_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValuesString[0]) * Float.parseFloat( + sensorValuesString[0]) * Float. + parseFloat(sensorValuesString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_ACCELEROMETER; + break; + case 2: + streamDef = AndroidSenseConstants.MAGNETIC_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValuesString[0]) * Float.parseFloat( + sensorValuesString[0]) * Float. + parseFloat(sensorValuesString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_MAGNETIC; + break; + case 4: + streamDef = AndroidSenseConstants.GYROSCOPE_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValuesString[0]) * Float.parseFloat( + sensorValuesString[0]) * Float. + parseFloat(sensorValuesString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_GYROSCOPE; + break; + case 5: + streamDef = AndroidSenseConstants.LIGHT_STREAM_DEFINITION; + sensorName = AndroidSenseConstants.SENSOR_LIGHT; + payloadData = new Float[]{Float.parseFloat(sensorValuesString[0])}; + break; + case 6: + streamDef = AndroidSenseConstants.PRESSURE_STREAM_DEFINITION; + sensorName = AndroidSenseConstants.SENSOR_PRESSURE; + payloadData = new Float[]{Float.parseFloat(sensorValuesString[0])}; + break; + case 8: + streamDef = AndroidSenseConstants.PROXIMITY_STREAM_DEFINITION; + sensorName = AndroidSenseConstants.SENSOR_PROXIMITY; + payloadData = new Float[]{Float.parseFloat(sensorValuesString[0])}; + break; + case 9: + streamDef = AndroidSenseConstants.GRAVITY_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValuesString[0]) * Float.parseFloat( + sensorValuesString[0]) * Float. + parseFloat(sensorValuesString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_GRAVITY; + break; + case 11: + streamDef = AndroidSenseConstants.ROTATION_STREAM_DEFINITION; + sensorValues[0] = Float.parseFloat(sensorValuesString[0]) * Float.parseFloat( + sensorValuesString[0]) * Float. + parseFloat(sensorValuesString[0]); + payloadData = sensorValues; + sensorName = AndroidSenseConstants.SENSOR_ROTATION; + break; + } + } catch (NumberFormatException e) { + log.error("Invalid sensor values are sent from the device."); + continue; + } + } + publishDataToDAS(deviceId, sensor.time, sensorName, streamDef, sensor.value, payloadData); + } + } catch (JsonSyntaxException e) { + throw new TransportHandlerException("Invalid message format " + mqttMessage.toString()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + private void publishDataToDAS(String deviceId, Long time, String sensorName, + String streamDefinition, String sensorValue, Object payloadData[]) { + try { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceManagementProviderService deviceManagementProviderService = (DeviceManagementProviderService) ctx + .getOSGiService(DeviceManagementProviderService.class, null); + if (deviceManagementProviderService != null) { + DeviceIdentifier identifier = new DeviceIdentifier(deviceId, AndroidSenseConstants.DEVICE_TYPE); + Device device = deviceManagementProviderService.getDevice(identifier); + if (device != null) { + String owner = device.getEnrolmentInfo().getOwner(); + ctx.setTenantDomain(MultitenantUtils.getTenantDomain(owner), true); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + if (deviceAnalyticsService != null) { + Object metaData[] = {owner, AndroidSenseConstants.DEVICE_TYPE, deviceId, time}; + if (streamDefinition != null && payloadData != null && payloadData.length > 0) { + try { + SensorDataManager.getInstance().setSensorRecord(deviceId, sensorName, sensorValue, time); + deviceAnalyticsService.publishEvent(streamDefinition, "1.0.0", metaData, + new Object[0], payloadData); + } catch (DataPublisherConfigurationException e) { + log.error("Data publisher configuration failed - " + e); + } + } + } + } + } + } catch (DeviceManagementException e) { + log.error("Failed to load device management service.", e); + } + } + + /** + * @throws TransportHandlerException in the event of any exceptions that occur whilst sending the message. + */ + @Override + public void publishDeviceData() throws TransportHandlerException { + + } + + /** + * @param publishData the message (of the type specific to the protocol) to be sent to the device. + * @throws TransportHandlerException in the event of any exceptions that occur whilst sending the message. + */ + @Override + public void publishDeviceData(MqttMessage publishData) throws TransportHandlerException { + + } + + @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 + + " for device-type - " + AndroidSenseConstants.DEVICE_TYPE, e); + } + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("MQTT-Terminator: Thread Sleep Interrupt Exception at device-type - " + + AndroidSenseConstants.DEVICE_TYPE, e1); + } + } + } + } + }; + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/DeviceData.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/DeviceData.java new file mode 100644 index 000000000..2577a21f8 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/DeviceData.java @@ -0,0 +1,15 @@ +package org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.util; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceData { + @XmlElement(required = true) public String owner; + @XmlElement(required = true) public String deviceId; + @XmlElement public SensorData[] values; +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/SensorData.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/SensorData.java new file mode 100644 index 000000000..a2f9cebf9 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/controller/service/impl/util/SensorData.java @@ -0,0 +1,44 @@ +package org.wso2.carbon.device.mgt.iot.androidsense.controller.service.impl.util; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +/** + * This stores sensor event data for android sense. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorData { + + @XmlElement public Long time; + @XmlElement public String key; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + @XmlElement public String value; + +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/permissions.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..d30a5096f --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,143 @@ + + + + + + + + + + add sensor information + /login + /controller/sensors + POST + + + + Get light information + /login + /controller/device/{deviceId}/sensors/light + GET + + + + Get battery information + /login + /controller/device/{deviceId}/sensors/battery + GET + + + + Get gps information + /login + /controller/device/{deviceId}/sensors/gps + GET + + + + Get magnetic information + /login + /controller/device/{deviceId}/sensors/magnetic + GET + + + + Get accelerometer information + /login + /controller/device/{deviceId}/sensors/accelerometer + GET + + + + Get rotation information + /login + /controller/device/{deviceId}/sensors/rotation + GET + + + + Get proximity information + /login + /controller/device/{deviceId}/sensors/proximity + GET + + + + Get gyroscope information + /login + /controller/device/{deviceId}/sensors/gyroscope + GET + + + + Get pressure information + /login + /controller/device/{deviceId}/sensors/pressure + GET + + + + Get gravity information + /login + /controller/device/{deviceId}/sensors/gravity + GET + + + + Get words information + /login + /controller/device/{deviceId}/sensors/words + GET + + + + Get words information + /login + /controller/device/{deviceId}/sensors/words + POST + + + + set word threshold information + /login + /controller/device/{deviceId}/sensors/words/threshold + POST + + + + delete words + /login + /controller/device/{deviceId}/sensors/words + DELETE + + + + get device stats + /login + /controller/stats/device/{deviceId}/sensors/{sensorName} + GET + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..476cbcc61 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..138f002d0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.controller.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,57 @@ + + + Android Sense + Android Sense + + + CXFServlet + org.apache.cxf.transport.servlet.CXFServlet + 1 + + + CXFServlet + /* + + + isAdminService + false + + + doAuthentication + false + + + isSharedWithAllTenants + true + + + providerTenantDomain + carbon.super + + + + + managed-api-enabled + true + + + managed-api-owner + admin + + + managed-api-context-template + /android_sense/{version} + + + managed-api-application + android_sense + + + managed-api-isSecured + true + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/pom.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/pom.xml new file mode 100644 index 000000000..91f33ca0c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/pom.xml @@ -0,0 +1,205 @@ + + + + androidsense-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.androidsense.manager.api + war + WSO2 Carbon - Android Sense Management API + WSO2 Carbon - Android Sense Management Service-API Implementation + http://wso2.org + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.androidsense.plugin + provided + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + android_sense_mgt + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/AndroidSenseManagerService.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/AndroidSenseManagerService.java new file mode 100644 index 000000000..a9f942fde --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/AndroidSenseManagerService.java @@ -0,0 +1,166 @@ +/* + * 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.wso2.carbon.device.mgt.iot.androidsense.manager.service.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +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.androidsense.manager.service.impl.util.APIUtil; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; +import org.wso2.carbon.utils.CarbonUtils; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +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.Response; +import java.io.File; +import java.util.Date; + +public class AndroidSenseManagerService { + + private static Log log = LogFactory.getLog(AndroidSenseManagerService.class); + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + + @Path("manager/device") + @POST + public boolean register(@QueryParam("deviceId") String deviceId, @QueryParam("deviceName") String deviceName) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(AndroidSenseConstants.DEVICE_TYPE); + try { + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return true; + } + + 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); + device.setName(deviceName); + device.setType(AndroidSenseConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); + device.setEnrolmentInfo(enrolmentInfo); + 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()); + return false; + } + } + + @Path("manager/device/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(AndroidSenseConstants.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()); + } + } + + @Path("manager/device/{device_id}") + @PUT + public boolean updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name, + @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(AndroidSenseConstants.DEVICE_TYPE); + try { + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(AndroidSenseConstants.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) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } + } + + @Path("manager/device/{device_id}") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device getDevice(@PathParam("device_id") String deviceId) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(AndroidSenseConstants.DEVICE_TYPE); + try { + return APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } + } + + @Path("manager/device/{sketch_type}/download") + @GET + @Produces("application/octet-stream") + public Response downloadSketch(@PathParam("sketch_type") String sketchType) { + try { + String sep = File.separator; + String sketchFolder = "repository" + sep + "resources" + sep + "sketches" + sep + "android_sense" + sep; + String archivesPath = CarbonUtils.getCarbonHome() + sep + sketchFolder; + Response.ResponseBuilder rb = Response.ok(new File(archivesPath+sep+"androidsense.apk")); + rb.header("Content-Disposition", "attachment; filename=\"" + "androidsense.apk" + "\""); + return rb.build(); + } catch (IllegalArgumentException ex) { + return Response.status(400).entity(ex.getMessage()).build();//bad request + } + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/util/APIUtil.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/util/APIUtil.java new file mode 100644 index 000000000..ec55710dd --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/manager/service/impl/util/APIUtil.java @@ -0,0 +1,36 @@ +package org.wso2.carbon.device.mgt.iot.androidsense.manager.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 { + + private static Log log = LogFactory.getLog(APIUtil.class); + + 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 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/permissions.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..44c1677f0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,66 @@ + + + + + + + + + + Get device + /device-mgt/user/devices/list + /manager/device/* + GET + + + + Add device + /device-mgt/user/devices/add + /manager/device + POST + + + + Remove device + /device-mgt/user/devices/remove + /manager/device/* + DELETE + + + + Download device + /device-mgt/user/devices/add + /manager/device/*/download + GET + + + + Update device + /device-mgt/user/devices/update + /manager/device/* + POST + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..e732f7427 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..0c0ec3ef1 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.manager.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,49 @@ + + + Android Sense + Android Sense + + + 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 + /android_sense_mgt/{version} + + + managed-api-application + android_sense + + + managed-api-isSecured + false + + diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/pom.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/pom.xml new file mode 100644 index 000000000..fc0d2f4c9 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/pom.xml @@ -0,0 +1,115 @@ + + + + + + + androidsense-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.androidsense.plugin + bundle + WSO2 Carbon - AndroidSense DeviceType Plugin + WSO2 Carbon - AndroidSense DeviceType Plugin Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Impl Bundle + org.wso2.carbon.device.mgt.iot.androidsense.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*;resolution:=optional, + javax.naming;resolution:=optional, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers;resolution:=optional, + javax.net;resolution:=optional, + javax.net.ssl;resolution:=optional, + org.w3c.dom;resolution:=optional, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + org.wso2.carbon.device.mgt.extensions.feature.mgt.*, + org.wso2.carbon.utils.* + + + !org.wso2.carbon.device.mgt.iot.androidsense.plugin.internal, + org.wso2.carbon.device.mgt.iot.androidsense.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.devicemgt + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + + + org.wso2.carbon + org.wso2.carbon.utils + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/constants/AndroidSenseConstants.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/constants/AndroidSenseConstants.java new file mode 100644 index 000000000..9666dcc82 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/constants/AndroidSenseConstants.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.constants; + +public class AndroidSenseConstants { + + public final static String DEVICE_TYPE = "android_sense"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "ANDROID_DEVICE_ID"; + public final static String DEVICE_TYPE_PROVIDER_DOMAIN = "carbon.super"; + //Android Sense Stream definitions. + public static final String ACCELEROMETER_STREAM_DEFINITION = "org.wso2.iot.devices.accelerometer"; + public static final String BATTERY_STREAM_DEFINITION = "org.wso2.iot.devices.battery"; + public static final String GPS_STREAM_DEFINITION = "org.wso2.iot.devices.gps"; + public static final String GRAVITY_STREAM_DEFINITION = "org.wso2.iot.devices.gravity"; + public static final String GYROSCOPE_STREAM_DEFINITION = "org.wso2.iot.devices.gyroscope"; + public static final String LIGHT_STREAM_DEFINITION = "org.wso2.iot.devices.light"; + public static final String MAGNETIC_STREAM_DEFINITION = "org.wso2.iot.devices.magnetic"; + public static final String PRESSURE_STREAM_DEFINITION = "org.wso2.iot.devices.pressure"; + public static final String PROXIMITY_STREAM_DEFINITION = "org.wso2.iot.devices.proximity"; + public static final String ROTATION_STREAM_DEFINITION = "org.wso2.iot.devices.rotation"; + public static final String WORD_COUNT_STREAM_DEFINITION = "org.wso2.iot.devices.wordcount"; + + //Android Sensor names + public static final String SENSOR_ACCELEROMETER = "accelerometer"; + public static final String SENSOR_BATTERY = "battery"; + public static final String SENSOR_GPS = "gps"; + public static final String SENSOR_GRAVITY = "gravity"; + public static final String SENSOR_GYROSCOPE = "gyroscope"; + public static final String SENSOR_LIGHT = "light"; + public static final String SENSOR_MAGNETIC = "magnetic"; + public static final String SENSOR_PRESSURE = "pressure"; + public static final String SENSOR_PROXIMITY = "proximity"; + public static final String SENSOR_ROTATION = "rotation"; + public static final String SENSOR_WORDCOUNT = "wordcounter"; + //MQTT Subscribe topic + public static final String MQTT_SUBSCRIBE_WORDS_TOPIC = "wso2/android_sense/+/data"; + public static final String DATA_SOURCE_NAME = "jdbc/AndroidSenseDM_DB"; +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/exception/AndroidSenseDeviceMgtPluginException.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/exception/AndroidSenseDeviceMgtPluginException.java new file mode 100644 index 000000000..88557cd9f --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/exception/AndroidSenseDeviceMgtPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.androidsense.plugin.exception; + + +public class AndroidSenseDeviceMgtPluginException extends Exception{ + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public AndroidSenseDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public AndroidSenseDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public AndroidSenseDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public AndroidSenseDeviceMgtPluginException() { + super(); + } + + public AndroidSenseDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManager.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManager.java new file mode 100644 index 000000000..7cab751f6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManager.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.impl; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 org.wso2.carbon.device.mgt.iot.androidsense.plugin.exception.AndroidSenseDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.feature.AndroidSenseFeatureManager; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.AndroidSenseDAO; +import java.util.List; + + +/** + * This represents the Android implementation of DeviceManagerService. + */ +public class AndroidSenseManager implements DeviceManager { + + private static final AndroidSenseDAO androidSenseDAO = new AndroidSenseDAO(); + private static final Log log = LogFactory.getLog(AndroidSenseManager.class); + private FeatureManager androidSenseFeatureManager = new AndroidSenseFeatureManager(); + + @Override + public FeatureManager getFeatureManager() { + return androidSenseFeatureManager; + } + + @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 Android device : " + device.getDeviceIdentifier()); + } + AndroidSenseDAO.beginTransaction(); + status = androidSenseDAO.getDeviceDAO().addDevice(device); + AndroidSenseDAO.commitTransaction(); + } catch (AndroidSenseDeviceMgtPluginException e) { + try { + AndroidSenseDAO.rollbackTransaction(); + } catch (AndroidSenseDeviceMgtPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the Android 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 Android device enrollment data"); + } + AndroidSenseDAO.beginTransaction(); + status = androidSenseDAO.getDeviceDAO().updateDevice(device); + AndroidSenseDAO.commitTransaction(); + } catch (AndroidSenseDeviceMgtPluginException e) { + try { + AndroidSenseDAO.rollbackTransaction(); + } catch (AndroidSenseDeviceMgtPluginException 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 Android 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 Android device : " + deviceId); + } + AndroidSenseDAO.beginTransaction(); + status = androidSenseDAO.getDeviceDAO().deleteDevice(deviceId.getId()); + AndroidSenseDAO.commitTransaction(); + } catch (AndroidSenseDeviceMgtPluginException e) { + try { + AndroidSenseDAO.rollbackTransaction(); + } catch (AndroidSenseDeviceMgtPluginException 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 Android 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 Android device : " + deviceId.getId()); + } + Device iotDevice = androidSenseDAO.getDeviceDAO().getDevice(deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (AndroidSenseDeviceMgtPluginException e) { + String msg = "Error while checking the enrollment status of Android 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 Android device : " + deviceId.getId()); + } + device = androidSenseDAO.getDeviceDAO().getDevice(deviceId.getId()); + } catch (AndroidSenseDeviceMgtPluginException e) { + String msg = "Error while fetching the Android 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 Android device : " + deviceIdentifier); + } + AndroidSenseDAO.beginTransaction(); + status = androidSenseDAO.getDeviceDAO().updateDevice(device); + AndroidSenseDAO.commitTransaction(); + } catch (AndroidSenseDeviceMgtPluginException e) { + try { + AndroidSenseDAO.rollbackTransaction(); + } catch (AndroidSenseDeviceMgtPluginException 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 Android device : " + deviceIdentifier; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public List getAllDevices() throws DeviceManagementException { + List devices = null; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Android devices"); + } + devices = androidSenseDAO.getDeviceDAO().getAllDevices(); + } catch (AndroidSenseDeviceMgtPluginException e) { + String msg = "Error while fetching all Android devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManagerService.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManagerService.java new file mode 100644 index 000000000..b31b86531 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/AndroidSenseManagerService.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; + +import java.util.List; + +public class AndroidSenseManagerService implements DeviceManagementService { + private DeviceManager deviceManager; + @Override + public String getType() { + return AndroidSenseConstants.DEVICE_TYPE; + } + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public void init() throws DeviceManagementException { + this.deviceManager=new AndroidSenseManager(); + } + + @Override + public DeviceManager getDeviceManager() { + return deviceManager; + } + + @Override + public ApplicationManager getApplicationManager() { + return null; + } + + @Override public void notifyOperationToDevices(Operation operation, List list) + 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 list) + throws ApplicationManagementException { + + } + + @Override public void installApplicationForUsers(Operation operation, List list) + throws ApplicationManagementException { + + } + + @Override public void installApplicationForUserRoles(Operation operation, List list) + throws ApplicationManagementException { + + } + +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/AndroidSenseDAO.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/AndroidSenseDAO.java new file mode 100644 index 000000000..ab12ac61d --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/AndroidSenseDAO.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.exception.AndroidSenseDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.impl.AndroidSenseDAOImpl; +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 AndroidSenseDAO { + + private static final Log log = LogFactory.getLog(AndroidSenseDAO.class); + static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal(); + + public AndroidSenseDAO() { + initAndroidDAO(); + } + + public static void initAndroidDAO() { + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(AndroidSenseConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + AndroidSenseConstants.DATA_SOURCE_NAME); + } + } + + public AndroidSenseDAOImpl getDeviceDAO() { + return new AndroidSenseDAOImpl(); + } + + public static void beginTransaction() throws AndroidSenseDeviceMgtPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new AndroidSenseDeviceMgtPluginException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws AndroidSenseDeviceMgtPluginException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new AndroidSenseDeviceMgtPluginException("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws AndroidSenseDeviceMgtPluginException { + 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 AndroidSenseDeviceMgtPluginException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws AndroidSenseDeviceMgtPluginException { + + 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 AndroidSenseDeviceMgtPluginException { + 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 AndroidSenseDeviceMgtPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/impl/AndroidSenseDAOImpl.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/impl/AndroidSenseDAOImpl.java new file mode 100644 index 000000000..30afa96f1 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/impl/AndroidSenseDAOImpl.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.exception.AndroidSenseDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.AndroidSenseDAO; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.util.AndroidSenseUtils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implements dao impl for android Devices. + */ +public class AndroidSenseDAOImpl { + + + private static final Log log = LogFactory.getLog(AndroidSenseDAOImpl.class); + + public Device getDevice(String deviceId) throws AndroidSenseDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + Device device = null; + ResultSet resultSet = null; + try { + conn = AndroidSenseDAO.getConnection(); + String selectDBQuery = + "SELECT ANDROID_DEVICE_ID, DEVICE_NAME" + + " FROM ANDROID_SENSE_DEVICE WHERE ANDROID_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, deviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + device = new Device(); + device.setName(resultSet.getString(AndroidSenseConstants.DEVICE_PLUGIN_DEVICE_NAME)); + if (log.isDebugEnabled()) { + log.debug("Android device " + deviceId + " data has been fetched from " + + "Android database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Android device : '" + deviceId + "'"; + log.error(msg, e); + throw new AndroidSenseDeviceMgtPluginException(msg, e); + } finally { + AndroidSenseUtils.cleanupResources(stmt, resultSet); + AndroidSenseDAO.closeConnection(); + } + return device; + } + + public boolean addDevice(Device device)throws AndroidSenseDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = AndroidSenseDAO.getConnection(); + String createDBQuery = + "INSERT INTO ANDROID_SENSE_DEVICE(ANDROID_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, device.getDeviceIdentifier()); + stmt.setString(2, device.getName()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android device " + device.getDeviceIdentifier() + " data has been" + + " added to the Android database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Android device '" + device.getDeviceIdentifier() + + "' to the Android db."; + log.error(msg, e); + throw new AndroidSenseDeviceMgtPluginException(msg, e); + } finally { + AndroidSenseUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device device) throws AndroidSenseDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = AndroidSenseDAO.getConnection(); + String updateDBQuery = + "UPDATE ANDROID_SENSE_DEVICE SET DEVICE_NAME = ? WHERE ANDROID_DEVICE_ID = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, device.getName()); + stmt.setString(2, device.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android device " + device.getDeviceIdentifier() + " data has been modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Android device '" + + device.getDeviceIdentifier() + "' data."; + log.error(msg, e); + throw new AndroidSenseDeviceMgtPluginException(msg, e); + } finally { + AndroidSenseUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteDevice(String deviceId) throws AndroidSenseDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = AndroidSenseDAO.getConnection(); + String deleteDBQuery = + "DELETE FROM ANDROID_SENSE_DEVICE WHERE ANDROID_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, deviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android device " + deviceId + " data has deleted from the Android database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Android device " + deviceId; + log.error(msg, e); + throw new AndroidSenseDeviceMgtPluginException(msg, e); + } finally { + AndroidSenseUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws AndroidSenseDeviceMgtPluginException { + + Connection conn = null; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device device; + List iotDevices = new ArrayList<>(); + + try { + conn = AndroidSenseDAO.getConnection(); + String selectDBQuery = + "SELECT ANDROID_DEVICE_ID, DEVICE_NAME FROM ANDROID_SENSE_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + device = new Device(); + device.setDeviceIdentifier(resultSet.getString(AndroidSenseConstants.DEVICE_PLUGIN_DEVICE_ID)); + device.setName(resultSet.getString(AndroidSenseConstants.DEVICE_PLUGIN_DEVICE_NAME)); + iotDevices.add(device); + } + if (log.isDebugEnabled()) { + log.debug("All Android device details have fetched from Android database."); + } + return iotDevices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Android device data'"; + log.error(msg, e); + throw new AndroidSenseDeviceMgtPluginException(msg, e); + } finally { + AndroidSenseUtils.cleanupResources(stmt, resultSet); + AndroidSenseDAO.closeConnection(); + } + + } + + } \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/AndroidSenseUtils.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/AndroidSenseUtils.java new file mode 100644 index 000000000..187649aa6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/AndroidSenseUtils.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.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 org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.exception.AndroidSenseDeviceMgtPluginException; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +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 plugin. + */ +public class AndroidSenseUtils { + + private static Log log = LogFactory.getLog(AndroidSenseUtils.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); + } + + /** + * Creates the device management schema. + */ + public static void setupDeviceManagementSchema() throws AndroidSenseDeviceMgtPluginException { + try { + Context ctx = new InitialContext(); + DataSource dataSource = (DataSource) ctx.lookup(AndroidSenseConstants.DATA_SOURCE_NAME); + DeviceSchemaInitializer initializer = + new DeviceSchemaInitializer(dataSource); + log.info("Initializing device management repository database schema"); + initializer.createRegistryDatabase(); + + } catch (NamingException e) { + log.error("Error while looking up the data source: " + AndroidSenseConstants.DATA_SOURCE_NAME); + } catch (Exception e) { + throw new AndroidSenseDeviceMgtPluginException("Error occurred while initializing Iot Device " + + "Management database schema", e); + } + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/DeviceSchemaInitializer.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/DeviceSchemaInitializer.java new file mode 100644 index 000000000..1b4935010 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/dao/util/DeviceSchemaInitializer.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * Provides methods for initializing the database script. + */ +public class DeviceSchemaInitializer extends DatabaseCreator{ + + private static final Log log = LogFactory.getLog(DeviceSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + + File.separator + "cdm" + File.separator + "plugins" + File.separator; + + public DeviceSchemaInitializer(DataSource dataSource) { + super(dataSource); + } + + @Override + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptName); + } + return setupSQLScriptBaseLocation.replaceFirst("DBTYPE", databaseType) + scriptName; + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/feature/AndroidSenseFeatureManager.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/feature/AndroidSenseFeatureManager.java new file mode 100644 index 000000000..1fb947ae6 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/impl/feature/AndroidSenseFeatureManager.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.feature; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.constants.AndroidSenseConstants; + +import java.util.List; + +public class AndroidSenseFeatureManager implements FeatureManager { + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + return false; + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + return false; + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeature(AndroidSenseConstants.DEVICE_TYPE, name); + } + + @Override + public List getFeatures() throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeatures(AndroidSenseConstants.DEVICE_TYPE); + } + + @Override + public boolean removeFeature(String name) throws DeviceManagementException { + return false; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + return false; + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/internal/AndroidSenseManagementServiceComponent.java b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/internal/AndroidSenseManagementServiceComponent.java new file mode 100644 index 000000000..4896302ea --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/androidsense/plugin/internal/AndroidSenseManagementServiceComponent.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.androidsense.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.exception.AndroidSenseDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.AndroidSenseManagerService; +import org.wso2.carbon.device.mgt.iot.androidsense.plugin.impl.dao.util.AndroidSenseUtils; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.android.internal.AndroidSenseManagementServiceComponent" + * immediate="true" + */ +public class AndroidSenseManagementServiceComponent { + + + private ServiceRegistration androidServiceRegRef; + private static final Log log = LogFactory.getLog(AndroidSenseManagementServiceComponent.class); + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Android Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + androidServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), new AndroidSenseManagerService(), null); + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug( + "-Dsetup is enabled. Iot Device management repository schema initialization is about " + + "to begin"); + } + try { + AndroidSenseUtils.setupDeviceManagementSchema(); + } catch (AndroidSenseDeviceMgtPluginException e) { + log.error("Exception occurred while initializing device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug("Android Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Android Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Android Device Management Service Component"); + } + try { + if (androidServiceRegRef != null) { + androidServiceRegRef.unregister(); + } + + if (log.isDebugEnabled()) { + log.debug( + "Android Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Android Device Management bundle", e); + } + } +} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/pom.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/pom.xml new file mode 100644 index 000000000..032743a6c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/pom.xml @@ -0,0 +1,61 @@ + + + + + + + androidsense-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.androidsense.ui + WSO2 Carbon - IoT Server Android Sense UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/assembly/src.xml b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.hbs b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.hbs new file mode 100644 index 000000000..f5fb9d840 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.hbs @@ -0,0 +1,84 @@ +{{#zone "topCss"}} + +{{/zone}} +{{#zone "device-thumbnail"}} + +{{/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}} +
+
+
Device Location
+
+
+
+
+
+
+
+
Operations Log
+
+ +
+
+ Not available yet +
+
+
+
+
+
+
+
+{{/zone}} + +{{#zone "bottomJs"}} + +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.js b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.js new file mode 100644 index 000000000..21035b3d8 --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.js @@ -0,0 +1,35 @@ +/* + * 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"); + + 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") { + return {"device": device}; + } else { + response.sendError(404, "Device Id " + deviceId + "of type " + deviceType + " cannot be found!"); + exit(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/public/images/android-sense-icon.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/public/images/android-sense-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4baf188bb1e7c0ddc75bd63ce3d3a0f235f0cb0c GIT binary patch literal 8464 zcmbVy2UJsAmoPjO3-t-on@E!$2)%bg7l?EsB@{8CB#?xvpmd}OCMy{IDr8C@_+dnAn4?YHozNINFF28kqq{wv1A?$~h8x4}9C4lHoCbF{g> zo~(mALfGyCMi`6m0I-RO1Lh*%hh4xnAGI$>Hj#z-cC-FRJgM26u7Q z_Vt3B_!^ix__{gBIC3f}a>!$40Rjj(+KvN@c!)&FVih=lrz;DLFQ!E}IerI0yD4z~ zu_$wWBMvopFF1#Uu!N9B3L^Q5sL@ECW(OC8ONa}JI*P)DoFu@aLNfOD_ChjFAQ?$G*xnu_ zDg76nf5I0BscUM8iK(kdNU4HA8WPfCqN*yAAPpIHDHTywkmg^w5F`q1hjf7d#oHC& z{U@&4zr~eR^Mc!<-MviR-5>sC1x7CJXm^y0y9bAw8V8@5E7H*&gSvB}p+7dP4)=2P zfjeq?xg$7!7qP7CKd^_x?JoA`C?slU=OhFNf#E{-;?j~rPEtm9tbSz5S;#;nQRx_0drbprKOYJ=Ke9f@RUZ?fJjD-d6PmLtB#vfl7=c(%vcd!l#O z2faUA-2O%S85tiZWhZya7jBhO5AHak+Vv2wfWc!k%nf3aANPZQd|P)@OrX>!9GdNx zokPcMxHa^A`-q6l5*dFX$|WXpB~oT0iX;7>huS1W1foo>X!6JSZ@uTuu@JLUVnUw- zPfh|gGl-kl!4i3IZ)5KJ7tzEHzOG{9v-Wwf(UoU}&XE>g{Hi?mWZU7g1Vs$8x|&L` zZ<*^k$tQ0RU&3>0=Gv9L2t&cwQe2>9V#fPhTVycY;%tdu(;K%MLAokTytv?yQ86Tk z@oAB!dNS`bwzC;3GezH_)#)r1@-Lsn`FOlGS0W}dAjY@RZJ&}Q1aa7{Od97%0k>sn$@LrF927$mlH$A7O1OtuonO?luBauPx&yKR;xg9fvI3?ZceVHcsPpT3TwG#w*Xxam>C{V3jLd8R?Ge&8WgZQtLWEnt`f+T96ZARSNOx`Q*SEUc4frqyH7Zn=pFzfNUGyCWzjSm_|eWkO2uxUAvChwgbO ziL2{7{AsjEUVxbD1~p{qdl$!hRZ+JZe(JvM8BEbC)s5n-xsP2*N{_E*9V4z2 zh(v?9D2RSn_#-e8$DhN@rkSUN@d`N>T)V+Ms~iH%pHXe;ffhZt3g$`l)LDDeZKviq zA*jaW8`a|!gqh_n8Vt;Bzzx;gdyf3llwDZ(xpGi6)Y!X1TwE&{xhx3T z94N=TO%4c{4=}G)e0M}GrV4pyWE##rEbbN;9&-L|Jo80&XCxZ@pJ7jKuq=!N!()0yQ2#;*1 zJnAOSMoVuO^kR@O`F9>i-#i%uJ!j1XU-+z_yiKR4nx{vO`aQoOEO%Yxc~iNsiH$?W ze)e~l^ZH|Yz|Hoy(-edSR{f}iSH|2e@7kOnLz#u2L*FYyNPK&a3@M8zeKNOaUUlTK z*Pt|mCW@)&eb3(KxrWR((63T1b_Jcfv_GB|)FC{YaIBC!t8vjuZ`mu5? zCv+cgC4iim?OL?0ZQl$rq&ztcSuHFq=L4t@zeT0kS~S%D@G9D$>C3HYUvE^9{YWn< z@Qa=%XqAex@{(nblc&nv#sw+b#8lq(h8&b}A`H7ZUo9mG{_u|al&s8cgL&pXMyEIY z3Z4GGt+l-KZ)Z8q6Xw+=+lNueOSkri^E$7`||C@El6JWjiAQmYM!hYRTyZGKH&>%nj9Dd)?^cPtjYgNy0n zqh%5`BM@hm&6^Wu#(@F%bU$r8zqILjJje1i{3Fex|EUK0o1>02%mqrzfCx^u8XC?wunR7iX500%uCIAf6M;-&uRj?zxZP;+zE_ zB*-ihEqvo{b1(aOZ2d<(PqdEVVQ-{+$#A9fkCh1B1wEDo20u5Xrn&ai&RFqSais-K z`8aYvdh@p2`On#LoO@$aI=2RsN0F4k#K=3;&zfk!c^hCjm(A`UwJ#af5|O9NnZJ}Q zv{vw1A10~sUO!)VTV_hbRS}vt>qwhSZEg0Cq3juV_;+o|DJ!E{lE>I>*@vAf$}F1{ znl?DQ!ogE%o;&ET!!zZ9Qe+bR6+BK+2o^eO*H2RSjr2aF1n3Pre_+azB>6iNWN2VV z!zNMA`f>0G?$$=qG1(TA8-Zt-eW4ei(xAo`oiTop8+P+BX%jSEG%;z1k~VkDB@RI9 zY5r_Fo672)&DmMR_23)*V2B`cuJ?6f326J`34o6jhKT!9oaY7JLd8xt6IlB zlBoR21Dwv+V1!@n*`gf#O>4dsZb-Mt+1V%=;BEU~^}Xt>)As#0JA>S1F>h7J-dWI8 zwB}}RYsU@UF5T$oO^JFQ9@J{jO>toPxn;#fVC^bp<=DZ4*KD$fV`ODXW0ntK^|^wk(~6$n zDAwzSQDFsK@4^A|*X#|yC6Lm)H9t=j$%(;b zwr|8`Hewq^`|K$xD}4@U{r#u+z87arHlphG8GyLI^q44dGvm-Cz~ANO{(!qavtN&b zkR<=Zv~$2&&|-RP)S5}@PMrChGhdaNna$B%!uK6x{lp+%CLb>7MPvI^a+J}ITZ zW-Y(HS-;q(9vTsY+w4nEW!MM8+6?6wefuLCnwMd8czCBJg1wFPT%#5{Bro~Ckwc!@u)U2oCUPBL$9!|#h3wjcWUIX55AsS$9 zc%JnA8w@PIzt@rDXt5Tx8t$h4gj6I$!fxU@i^g3fvP{JqeK0dj^X!!({_E0krt<#h zg-_9&7WVz8`Oe4HnPg^XHDwi2o)*E0 zlK}~PS>Ll{Pj?~9wR@xuiT+Vvt-EK)d40yL>V>{w0O8TH;5Ca*J!Tfi4@;}`hK7)h zj3$~~Vwx+AS zNnt{b3!=kD8z2CCdzmn02;|(VAtgsA<23fSTU3M1uV|ChVdq$AX|nia6`rW*sk@k8 z74he!IJlm}sipPg=bj#gU9*Y`op=$k>nAh9eN)cgg1JKs`l)X?enni%mYEUo{h>6!I z=(jMn?0BHe>s@kW-FIIQcBStyj%AfF%r`HTke-DAV#wLT;cl5lFZJi<&1$F znP18oq}G2e7=1`t5Y>>BYp2}TE370bE-rMZ&)&yxgk#Vvt;cgubvWariF1@LW43Ti zk6!vKaZYZ~;G4<Bu*$Oybx1VVYoP?=%l*rC5#b1$rJ0l{KBWzTJ+# z>AIl{gp#I%lg?#U0U2qd4o1*iE4#cP+s(=Gk3%KKVS7Sl7fC}{d-Bsu-kyT;8gkdL z8^1BudfuH5IuEjyG5P$ei0VCaxnX!r__`9>xw_pbHj46mEz&)YyS=E+Fa&dnXP!K0 zD?_es<+mgt`HAq1x=P`sf14t30XRR}oG5qaQys)icw-0#P6gW$AziDKqKwY^EJ?KN z^If}(1|7euwWn$_o#@>gnL@H3$?|q|TmvO=)$W|?*j4LNRK5t~rrO#(%4!~r&Vm%X z<~C1Oz3kzcj9qXN<4oJztlTGE~@7LUI6^9-G5Vc{|nMTmlZ^=OAZO28OFwHAOUE29I5O~yD4vW%S22Lpn|cUA-TGV39%Me%%j?lSzAZbHvmaWP_N^9WgOdDjGgA&Ty*04*H> zw}4tF{eb?j{fi&CvzB}<_#z1er_rFD=vat?iK*8Hme`HSbwhl)Y6VvDLwxhg;Ht#r zc==F$WY^I|=?0R+zkGeEH>AD3!ArMjb>M>)-bT>*LM{1qjhh1!X_F)GS{6L4*JUXS zmK%ipU}s%zgOc?%4x%o>FCLu!9PsvQk`4%2{w4{&Fghv>+fLrc8duHG%vjR_iLjRnAIGT-NTbJTA^iQ z`ss&P5_G_(@Xdl}nJ$nKobQd)VIlfbL!fqp;^l9y6H#Y&{Q z>OE5&skJV2VAfgWIrQgF37wX~O{gjA3lHH@>8m^Zr(I!k-Um^y6=CJbWyP@mR#|1H zzRPLjn@9CllSlW%N+;ghm>M6Jl@%*^)rH^8Y?{^|KGlZW%qlgU^uDiX#q^}VVxZ6a zvK1pfeQ%tY$H5f)rsK`Q)@i!186p5x)Fa$jAu>ciIr)a~?yt9;5bP* z>nGJu(gnMON~-XNv=>#u`B!m4U&13Kps=RBwLz*XcD?Y3tL2u~$o<{*`^ITK@zl(l zv4)eclUdfgq{>R&PI{P^saWI$02Y4oqbro2;u%2?hhIdS!Wx^t^BwFiFK=z(Bkqs8 zt&L3t>RZ6fIo74LQ7lUeqO#!a*`db-tYa=h{UyT1Qv2{al{auF0<`&cI(^?N#OL~0el|ge9iNF)kPLHZ*$V-@QjbBxU)w%X^qWh>58(8hUNcRQU6byDIPeZz5%>Mp1YFkwey7-Z zg3ai1(@3h(2mJ_+B8_+miR)5N7%LFW>Db9He;>LCApaCKPN~a6pX{B1)~#ZrHCx~C zkzdsgDIH#UmK~MHOV+#iS_Wn_%0ZxZ`H-8(u5EKCo$s7a(88LWrv*uk%&=R=B9@k; zf%`Cb_u+tdIb@n3cpPnFF816#!Et?Yq737I7i1$?b~wK5M#U!6!H_^ouFPDuHt`M~ z+cHmQ)2Aqp2@Ik8CDFM;byJUBo_zw}@VL*{PWCQ#b6|j(IW?706WCE+cA?K{zRgVu z?^P@6i8~>SEmJ~Ia}n0s<%??moWh;uQZyspT(i!&g1v=#@q}DrlFs-<=h(T|18b`p z^}brPj_$u!HjqzHg?wuiCsa5Pn8{WjlpEWcG%ZiPmrP4<=AvNWFoi1klxOB=4R1ex zBB`>W$5JV5efLQz_H0o6Yg{@~%{EZQ0!}dtVG>magC*!`Q(OuNeLPnuEFLWaC(m@H zHLG{r+|Q$~d8l_Zuj?nGTiHfXlY+to=k4Z-%XS-$$<6KVQ{$a+R--IH4;^BpAy>t{~U(%m<-yuh_|; zO@&F+=+YI-SqDzI#nDz?pA>3K=nh{W3r)u;2tq;{88`K5`fUhF$zV}b->m#+&8Jk6 zF^=-Uo2&1MQS>9YpdLkB2uPZ3@%Ys2qgWnlA zN08AJb3E3(C_k4=g|k2W_%4nkG#-3E^ID~4NxY{(%PyDEKNe@FxINWEau3yW3rs-NeN+Wwjf#V#YKyv)P}+O79V+jW;(u0;97E^KIRmyo@s8a~rgq zU!5xa@V0q;UU37QkOWGzM?dR)*DmK~ksU4y|J=jSCtlvnTFhJbs>Q?jR%^ICF`^rD z@b)?mR@uONa^J6^-`3==ppPBY+Wm~V8>E84m1S3+((_lX%l)Rk)PKyrUR+utu6;us zxO4DkAP-$g9vm7(dP&=mhfSE84wa7A00$&)qFh*)6!t7iYU9pe?$_wxFiTq~y`!Xl z_q3~j0B)KpXr$7u$tp?y%E%yP!@5FhRWFGOQ{x<38c%DZ0}0nR)VBwtXL=;q&yJbh zfJDj06G^$QQq7&d?#4l}nns)PK^eIG@jo%OGsS8zyrb3Bpt8YE=Rt2u>}H@2?@S~f z;V3(TS{ybKNgGy?8)tV-CTq?&BHHp7zP@yo4bpKZDk?1rn$A-?osN;1x1^VMUV5N3 zT+ltJejISio)A*ZHxWQFQfobi4EbqnV-N-DWk{{G|61I-ozLCcE-FjXmRH{C&Ax8l zV7J^6%$e3Q(1^-9z4W?muOe(Yuv3|-G$N#cvaoB)=j}*X|APd;V=DShLMa$uQ8UBA z{DoHVS10a5Ddb3~P*Jgrjk*7hsfvY$e%ko7%)6>;vd$#uqwUphgev8Ko+O zi7LT+^!WJrOC2;+nw_zWR2ek8A6~DU`DGaYknVY1O&0yDYmFT%`3QT4_m|bZ+^m2> zWqQ)jm01phQvnIaeyXZ#*gISZ4hpHlkbNppKwRajVaRAbbM~xx_qXOIdgSpk>jzYj zui>6wYlojQlm82x@6av0)012cl_Rn1-sb~fB%SWMt}HUE}?)(xKwu5L_|V#^oontP{aUr@gD_iyvV0B*j)ZU6uP literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/public/images/thumb.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.device-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..1524c56fe77e4f59ccb87cffb7684dd1c5498795 GIT binary patch literal 7888 zcmbVx2UJt();3Lw6cN!#M??@6LTDjC=m-%3Cn6vvNC`D0lmudE3IaNah$tvk5X9in zl%kM;h!mwmsG*}&Ly;yR@EsiI&b{lO|E~3YSt~2&?Ckx%yFTwe``o!?Zp?d7_#hJ# z6EDKV5Xr>EjN1QlvICUXvq8eZj}YF-27ejnh7WS`M>FZU;+)Zv2p=bRG!pIPdfo3M zT8oK^)z8z?25)0_QNso2qu{j9qd@fW1*Dmnv~-BRPA=YPyreVQ-4hF!TCA#(lJsFhmEq_@aRfYE3efaV6MTHl%>K17HsF_| z0GEM@PQGA>f+E<*XWy=$+yQtb`foMWwqQB(hGoqv*7Qc}~`H`IsdsY3N35F=HXAxu$SRUM{mbY2~*ZUFmB7J&`G zJ7HbWf9>rF?EOnt@xRJy82F=|@Hl@<91inW7F_bc;c)>TIA2Kv1Ig3Yo>*60P=MTi zg#I+x5bf_7h;}{ikMoiI>0%Aff7l+4cG|bkRbJ7_$xR*&Q9;W)E32!?yFuNYm7vZp zXb40_>X*Fh|J8M1Kq>Hkp8Q+h{6zwiasTpPRRG-ltB%lEpm_X&Dv7^u^^}Q8cnx8w zXGt9VI?SE+h>+g6y!W={i=sWd=wtTi*rx){T>{xTFW45&6nF~T&8DEI3ZJZbHJchi ze)IWaRsBaf{+Tql)792bW<%Eu4%=Kic;U0ur&G856gca60;U2Lwzt=QWD?cecmlA> z(>$3Q^J^~A$^mX|KiUJTr}utjPH*moE)$2Cn6~a^$}llSfS5P|2&v^}VgobX7(1{} z&|PBrM}j1g8Q{2~tb1Rki7&IgZyv{(2#}D!eeQP9N=ZDR63-PdzN^r6*JY3XF?bUbeWWr)FKgKHw^BL6T1`!dAdZQ2L z#_@Nq2WnH3YpVhogJY+X?Z35UXJ><(`-*ZNbvWAE*=6>Z`_NgTL%wxwm6es|A{6W) zb@L?w3ab=R74P1j5&CF!aj!6hA!^IHQ&3Rg<3J#+B^TE0ZuuC;i!(a-{4B;zt@tUM z$0*gl>LGr9e#_7Nx9vQ|J|7g@2%RJ6X$LpUS5VIEF-m*T-ya-(Qm2=u-88nfwdKz> z9Cb^<-wc8HnD#bcdIW+Sp&%zk`*{cL$6ACVpy37fZ@Y9{o9=H4R4zVOy&wCjxfw^D zFRW5{U=fS?&W>3UsAj{3tp~cdJpRq<(xoLx3JXkxB`kc|2;@+DZK~x7wy5IWk!nfe zN_$hn$vk$Jn?j{*{#UPF9eA`d-JW?Zn5rj2;ei3V4@{P2HAkIk@-#9sdiLBbH83N@ zw#ApVHnlIyJ2FVg>}E(m3cZL)bANHd<2V*r@J(p52m9y9iHV8BQ#1%lhl+}TItEjj zQ&A#eE%(#-56+NDE_+fH8xFNWx*0-u+Zmy% zmAe3WmCpWma{ZZ0zq0L}?mK)GO!8Q)k+85Z3XY%Y7}1p+v)0axKTvo-$wNgrfgz_D z__co}hF3(bt*@u6PmV*WaZil(@`DEt#@fTy zUmrp&-5XysUz)J=oBf=^%E6bW*d{=)?DD3mzoa&Ji061se7JMs`pNh%0XDF}jQG>9 zhlNGnFv>N2IIB#3SP?i|G#XtpG2tAMJZ5AqO>|Mi&~x5rEX4^>OjL=crlyku6fu

kKhaelc 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 PcgzSQbHhUYYZ3ngtLSEh literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/android-sense-icon.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/android-sense-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4baf188bb1e7c0ddc75bd63ce3d3a0f235f0cb0c GIT binary patch literal 8464 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/myDevices_analytics.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/myDevices_analytics.png new file mode 100644 index 0000000000000000000000000000000000000000..292097a4519333fdc117e5c203c470fee82c9ec1 GIT binary patch literal 286419 zcmb??byS z$GP{Ob9>i%YrTKoB=D_oGLzYR&z9N0{UuOAP7>$Yt7i`$Jiw9qB(C`20s8KP2N>m; z==VKC^5o|C7jy$@N%04Ff4zP-=SAQ5Jhl0xZuj5;7QtVC4<96@klc4-*h|SuU@Sev z#3jZ3YCvjw-$iOKp=K{;ZE0y_W&c3T)=1yp$ndq3nZ4<2Nhw(cRWDrP2M=C9kP?6Y z)p=%T-YEevo_KqMD)=o7`3N+LiF}YDjviU@iFZVA-+V$3@C(e*c7TUY?S2>RC9&+vg-I9}e*r)3;w~XKih53FH+blM-FiklzFT zYyib|?Yp`p{1^Xe(;b$-LX*(%?;^wFvlyQL-T&7WSWP$+_&<{kp6!bN*>E{f-W1H_ z_V{v@*u`-T1pk?Rk`sTi2Ok?;t-jAuv$5$|=`>W@^9ZH!1@IYF! zKKD!XQ0;qVXlJw!6^_dNXMt5+ubRs-%log46cac9e-dKtiC11_^y32K%4cGU^a}56 z_DBspdj$A(^BvheF`5wmI@w?AD}MyXl3>JsKBf==WM3ok2QRDXqaMDFL_HuWb^7)Q z?yChDPn<_r$ybvoLy$@OvZiUq^oP;Fr#7ZRKRfX@Nmr#LSjnnHB)X~0PWOrz60ib= z!?D6ee~iIG^**(x(L_Hin7}ULvslg{#ex`aedsYRkU6LSM?!xID$@zF&jPkN_vrCPGUmg#p-$QPoBBzCQ&A(uE(fn3x`B5bhd6a);xL_i#5Xa zxgZwRvzgDROzhAMn6%&wcy?xw*^(vm_tXamZQ9kT<(u;%V%DW&f{z5w=yci`ypOfy z0HQzO+V-@QLmE9SPQu;&DCV3un?+lHi~L{WxGlI&7ZXI|?(%b6wNpV_{x%6tm{$}R za0H)Cl})!pU$Uh9&PYR;ze=1`tW-5s&7bhD65s_x;GsgTHB6!u)p7Dp^WB$UpTZ~X ze@b$87|ru>wP=%14v`HU=W<4M+aM$e&f#V5ai?o34osmS z?W*u+@1%J{OmSG$G!wuuh1EtHKvvNE|LEhtq%9wD^KAFSHhWHOibQBEHmh}}=NtH( z3UM9Fm&ymU#s+x;4`>}rk$B01FJ|ZURk7_)--MNZ)03=sWLN;Xh6hU(40jF z@)8+B-n*RhBJv5D#45{qT5#Kv3uL{yDyG1kEZ`J-#X`oNg#Fw3>+Um@jM0OMkKBB} zIZST9txp&qXiK)G{$aU2be$e0X7TKC%8B2*WM8JtJ8)6=X+rXNq%^fj7|i(#gu3zz zX|>S&SDaRUS%R(A!ZG5@Tj`39WbjIA#;9d!lR<+4k zSglG$K118jur;lVM6Qi-4k@ccOP{j4$J>tWMa)Lym&}V0L5bGAx5ry^Y3yU4`PWn| zL~@THeBiY_xZdds53^Qltk1Sv_Q4GOk2LD@(a`j~o7uC<4OOJKz%MadhgT+wz|wsZM7bW`c9UoCKhc6q@pfm@q+%k4 zLuReHB|{T>0udkCt#2l@k^9T)7J$h9wVpNVm0H&HX|1q{b$|~C2}Te>Oq{b};iS!E zi6}y!xUwMP3*U`TYlPR0(z1)Q9Bpy2HjD?>n+tMW!%2anutoXR*G zX@jLy*d5z}*XJ{c^LCCZ=j*bf@-Q*RcIq?AoNlXuCZK0Q6Q-8S1@tSH!JV%Q* zfqOKt)`XzG`w<60qeTv_=0LTdB7ix4mvp~tVZ3_X-9u?U^3v^HB0)5JTy+gV(D?CN zolnLWv*HCW6AZ0`gw+(HLEY=jeB`>l$Fk~$$!{)|p`GueUKhfOonQK;_e6G}uk62p zvbQ^6mmYaq^Cb2mNnDQA??pmDI^K-UrUXA`fFE9@%TcR7a+o!rwqhyp6Vm2<5s~F` z!>bY#|Ha^!1K^Z7p$aVXCC}=Z@u}L)rKS*vIajr`;^C-N}cltT$_%E@^hOPM)WRa$D*j%*S}sJg=Wxxw~=jfW`Uu%$ctW z;kpz>Ywbno9J`UN2a9+tRNIZu_Ws<4(+&?4mZzY^$t1n^AYgNpS$9oQ-uNpGW`OQU z-}h14bv~8-5ALK`$AJ8z!O6U#x$Sw6!sxML^EfzcEoDyk?ZcZFppubxs{Fj9X<-VZ$pw2Y%vjLUhnf zxj5J=TI&lYUi>8}3iw#a(GCVYs@wm9iNp>=E}?2H`4BGIlg#>Gl!BsL?^yQE@4|BH zh@-v@iG9O>w>C$>Ch8(WwTFbZAMITn0PW{QqEUAntR9?o0m+^xVzB|##@^Lr@khO#;LL=b9;q6-hH>df@8A~+qCap1mtM_PUhjv z=QK3He$cPG632v>N0Ul*D8O#oL&BOg70O4M(wQ~JOYqH7_|NcjvknMAs}`py+sn`9 zjbCkIou%?C_2>yC-)1;CY|i7;$Y?>(i|A* z|8lI^8z$wBf9>*(S{=>PIWMvBu4K8X)ylXl4Erg3EpM?ts=%|^w*YUU9Zj@8j!IZC z@+zQByJgyT#UXyA(Svo;^MI8ifiqon@sx>HM7iTTR@qW}B{t4!)?gl3h;eJ(=2jK8 ze#Yfq3f-igkoELAJ{EL7m?%0wlycudsIOGw%A6l3CP2#$PPS3YUc@E`{{1aob*i-p zCEb>YhtmLki-V||>qFSt;cVW*>ZCQ?q;CQj8vvo9z7d+H4JRli5%cKB_Be2P+S;;@ zc{w4{uddseE~%5y2KTTRJ!?rbYCk{#i^B21*sJPy`(^b9;bVy{8G%zA|9e(FjdpsC zt7vSnV8N`fZO(uwdbN=F0gNoeeVHRB^RtfbHCGg?DShabZjhbmb(L(0Ax zxSMmpf5$0V8DJ}{b+5L6CyP5zagSwPbd+0!zVE7xb)FkSCs@pApO=ROb_fZysTbN*Bkd=`LlP0-NGH-bNVp0c( zB=*YnSa?P;f3N5DA>5+SvfWNZ2HU9De=US0;dPBAj&ui2j**C!KX#RgrGKz1N2z~5 zLGpvM`)wdNkFiYaJ&AAWJ?W6NIq8+;(EsX*E4oFq$B!Txx*lXpJTI1pi##0h!>84P zh|poMf<@%(E>(iiPeEFI0U_Q6+WieGSVmH6x`QjwWPXSZW%sddV!B{bzobC%<-8qp z>6T>cDC6i!j+Sk2qD%-5c!%Ssd)jGp|K>yq3G;KFDrX3KUo;`q1?|st0f31?Q+2z7@`QmejwJ&Y(txWq3ZfR1<^t@kZIBpV^mmv3 zHbyHHk~VB3*$>Sb{nfON-%?*pJjoM#c=M2{zHrPG&bG80#ZyY7O!8I)hBLMw4DnYHOeD0w@gA|&aWUs%n9RUL1N(IS0MqxO zme$@f)gN~1V^d5;uI_V@CTjQdQOrK*y5Zo>&6f0(1LjbFnKfPE?>cr;sVJTP@Ip^4 z>4<}|?C*@~FHZurX+m@O=>vioyS|+~K7}^T@@7tDvBn#Ib0-~~$mmmhW#B)3^3ttv z+jwY8Q7n)+>Y4U!H59Fj)klr-CW1ta@tFNxAgEU}Ua+OFof32)lfxV(K9~ZD29?l*? zx7x=@rpoBhz1KPn710-~%MGf1v(O9>B)+XiVqh6hD`w*$? z!Ky3J642;z_&U7gsT7S{u}Ke$`e0!$(Z)`sJdaW{us^q9Q_HD?p!hT43vtM+s95_x zUd6GEqqkL8S`YC(1_l!Q)f{`(!YJ5(P*QMx_XD2oZ*M)A+11nJmDrvsa9dkPs--wR z%}kg&E0>cg&3M^B@=NbcGx*PVh)aWfN1orKwqV7q?JR%@>3cBK)=r_7!O4XCWO zt$L%UBmEEYle1CRE<<`BM zG0wWsTc4oE0T?RN;Zm7FMfp+(_F&p=;FsgWv$Vy;7e<;r$`oQYorxB6k;Z+;7gM!C zEp8SCj4bU(!bzHnos_xULkS;v^rSjN=ycwW*DnuI8K_CEsK3!omZnyJZy;(o;JjM9#8_J?pj z$FG$fNJPyO;g$;K-phfave(smA!`LC1DynWuYPTmKhwj`QbRS868N0 z-(1<1z7nBtg+yIh!ew1T%Ww2)=sYm$IwGeo$A9hNm(!y!1|}*fhw2JEK&7CbJCS!2 zL@%xm`W8tw__5b6L9`rC!G@JoW5#T4Yu>gD-Uxo@G=F5ndEjGdojWGo%W3Y0bWh>_ zyt)3ubk88Yb?=muW;17_+r70N?D{l+u(sCGZP^kAuKA){2$ofSGM#zD{;uY2aANok zn-c1RmXAWWud41Q2tMB!VECmIfp-&#x^rLwl{N>~DBXS^R#?Ugb9!l}+ zArky1u(^@+**|e(Xu^bdbc_M?CQ<;)<;5>K6MY&eMp zV2xA@B2XYw*aS{#1$8H3HpD5dZ4FZY3v#;0oIrr^?kCX!iZ!lQEjaaGs{Z=m@Zb=4 zwM`3D(EmiHz*U3y*Ru1$3Gcj*RNV#W9$X`pO~b6s*|>+&QA-Uuf?x4!;DH8 zLMxyDSPrG?=kjz7(?nef*07WiLRoR35p3zMfJrSET((x8WWjXj*k2kUM{QmHVZ;jK z3{yw5>V-kUKkGLr-DjnxB!F*UQf_G)J`#OxN_p*VolRc&IXI)*IXzr8HvZj(NU2gp zcA@!UGmHyY`K^RPC8{Ffr%xe;%h(@~KmfoLgS(pRT_hTw<<5ui-W9m(+8L>!pFFmZ z{08b|u7`2+!UEc$r_|xrrF-2)HESVdGGA6CEQTJ-n9&pC%D z#h0$fHB#i&LSylD*FgW?pnw0j-6tPDO%TLes(#{7!GmfPNdYle%ug~9hK(5DWYqZj zmt^$3Yo9vXA=i`!v1WtRpNhFUWP&7~dZ8lmsK1dZG0#`0vN*_orEv#<^5v2I;LZno zttTHREauwltf28wGV}arLi0HPS@V!hc9-KXFc3EtE$u7mGyVA?_@eyrL$9=leKJ(# zRr_h*nuUSg3bFgW##IAqwP`X^QP4GA<72 z@0Z3(#NO7HoS1NuM#xml`aj8W{2$?#UrYNqc9UeXuTEgl*=-BU6Z2{;G^*%E${T(8 z@NYr<9W7UX9^NXWe+$WABz?y@tW5j|ACaDnVY%=A9{AUFby)EqaQ9ye+6FLG|LMhE z06YKRh_dhh5c|eI;e+5GtKNgb16MyWl0OjJQcRtvAMK%zQ$^x&Ito z0mtdRy6ShYPD+xn{+jK*izX(x=<_&iEu91ZNER1fp@-c~qTMV19E2SP8m2t`d!ANU zR_wo^58PNh>|N&ET||1gM8*(ZB5TRNjjo649HP}~@fU?a!(*hP*zncY_xqi$5a-64S+7YsB)n$YeTtHU55>kLVB^S^aM!F?l**e)Jlzc@ z$bRKm4hHdX{I>!03oXgrw1PdvFex38%66#%PsX&5Z*PuaLZT4Xx(|kp2LrDr!1Bs{t-2C zQ$G+Sgk#sD1Kq1{;w#b{Qmo~7#OfVhI^DT&vawjdHen(1=1{2bBQkHZS{NE#W4gG? z#!d0q18UjMJ+?y4CZcYSrHE?j>;F*y$nZrEKSwHY?S0x?zs_C)N6Szh@{gCB2G{+2 zuQ?od_L?b+UUPxCZ`bM~`EB?2cAZE$`)5E}$mcR%Z=X@+=l?YS(vw><*jXAZKz-ZV z6NQE2pAH5tCQtdFU@fc;iMDh%#fXjCIiq%K&LnV?>yD<}Jq?yG$1Wy(LG^2kcGobL zXtfAOOnb3E;y@3~^iGMB3}or3S|$CUy<9<@c>Qc%R58n|tor4kFZO&dBLB9Jf05)Cg8R-@25nt?I-SFk z5>9=RGT;6&zQ`q)CbDj z-07|IjTdG5$pD8?nYkS{4~)byy?`oZc$!W zrH?0~;A_3&ek-a@MbPU#%`1p0l&DgAqm_pJVdjD{Jyl~E?J`VM_FnWRFR&M`Y_sm zhNn|APH*M8mY7yD23=^0_WSCbM+B0-yMrRb0rM>Z&cVL?kBCy3&{PG?Rgxm`^c3!uLh61-QOrY@B8eg9VqxO#?u+H!8uSdPUkTJ#(Mff_ zP7`i67nz};poU|_O7M_@1@s9_FN8{|E)-~oJiMOm&ksh!r+qVTg?;BbPv4i)JnQfZ zgjrQ1bT&-(HN^!zm3L^#nvE@EWCweX`GUQz-fn2+$HS62cldUU&c1buW=)jqURpaZ z9JXHRLyis}^o4O0OOgiCXPd!{7u;@G(sVWat+8{OF%G7Wm}+pl zdfl6CWK!}CI+w-FG*nqNrgZ#^*c4Y6+tJpugSd{Wa24 z_=(Sa>A`L)@wj}p1o#8qmYGFaEw~ev4 z@=F+b!86v|8J;<3H)7tQj~bkC@W*K~1b$vCIHD_baL9i$Q+fQzq+qLlYgBw>0SQ}JOiRoxmm~INtG~W3o@20?$*QF6)nZdN(GBn7~T5E*H z)?DFRLEvKBxum!bm##W`GsXXAK8cDvxjEe$`+daE&Tum+BxdUOpf}c&!Y|frt3Te` zDxSXI2V34|`w9)O(RwC8Nnzz#j_=_(^A7gn{guc-jBjrSqmWjQwp$aNblb0$t`DNK_ zVq4vfnnxS>M+F%7Pn=@5SM*^o6@>V=e~ZqtA5 zcQtzLK{YJowN?B2p&sJHc0d1Pw*ZZDs7wZ6u-+FII0L^m{QFse*B0$b6Z5lT{3Pxe zmVg)bWF2tpYi>G+;KbXV#p#7@!XdKx7E8SN(|JGJA+v3W*{I#`5Wz&UR#)<7lxu`& zQ}fI1rbc0dAQq)1>czyG586hv zuI%m>7cX`(!f(}FSE}WTG!qQux5bQSU0V%C=cu=qG@i8R5b)#YJO&7SZxI&Lakt^o z)ByRxIKB{q5D_x|71tY!a{7Ax$y&BYG+QB9Y9GeJ`dd!kwm8o}5jyEEE2wxkHBcxq z2E8j7_wmqtJ$4#i0m`mIW>sy7qlc;yGn%E#O{EXP*nSb~GbK$Y zePlxC6B-(a3Jae6x_9lqfW=#F#Gs`~UrZOjJ1!j%1@XA;dsP|c-4@mVBxV1C37R|W za(i<&etlKOW_Uv`iZo$jei(-<7LI5*g4ujU*~%oC!2FDaE{@5Xn(PJj^FWZxvpl6& zuujX#Q9X9rjzv#rEGNsS{~T}cgKQ67-(RPYPVN1nOPoLg+MStK%>psUV{7Nc^Y0CI zMjGoxHQu|dkDL=Peq8D4aHL!l5i{0z4LJkf5-mi9&VonsV7AT*gVcD;xhNs;uRE;?eCd!IB+v5p|m;1D7*AQw?aKWrp`tk#+`B?`;yT z$+oEg<*K}coqjZ^$8Wu`E#cr;Xl;BT=ultWBfMvrAJ>bl(qQk^L>hk(0{u+yaIWOH z1V^N5+s1qM&98Mqk`oqh8(}j)zAWf(Jf$Z6UEq7wawm{nA}yua6-PFCIBbnFY|w>k z@JZ1rkz|Lm=o3adIjRZ+!@Nzf)4sQ7W@h=RJNvgAx-by z)oC@B0dKc2Q8tnPYhCznlQcx>q&d5ee)Grs6KsjBc&dw7i*IKS7t~|*vxkVN@1n}2 zs_7GRu$EY%BbDfR8%-e^<=l52kQ~BO#PcQeQrG4Rzhfy{4k-#J``8gxcM*<3JZ3rr zK7Ij=TycYI@xkXL9$;fsI#5S*LqHtJ`K8 zl5X_%j1Icja-oKZ=$Y6b&4M2-9nZ`oLaCFIKYY|3^*5J1$r!74D3wA6X$)o^%7@u3qU)v7Y$n#?gp zR)8XnsW+ni>>P$Xg0{c#nQ43+V;kAVQ__U3~6@@WTY0dl|Um>$e zj_4qRq;F2;#&&3C=D*&FBxmJ_NE>m!hqSllo;feypIHm@T+CT$r+|EZzqsnd(C(4i zw~G5nA9*$D^dRZWhUbtFRdQO;td1hA7F@Tv6m zeg=@6gg73Z;;LUoV@~?Ky`p17)SL%sUV#!7bo=Gqc=oW}%}+*}2?wg8b9EIxFmDXK zYES|q6M;>pIGvEuK?jQ&m0*Nm<6hSr= z-cD_-do9a6e3-)5!so!1ju5?Vib&aBnQ^(j)iTI4^apP5b? z2Q$dI&{zF8af*~rLK~(S`+ih<(h;IWuf&O}x|wI8!5gx5B!NYkS^T8h67%n*-~iPI z@@&^Bi~$tKO)$M@>Leanz36%$_mZiOfOcV4W4N2+rMs(AlBMCrIv@;zniP7)T;P_* z{S-efe2mD~abq$)GBs8EVFFl4W3mhesX|{gTQ8X=J0IA{;x8~E9pgi8EY{)O%+|0Y zp~@CG+JGvqmo;h##Z};xg`Yj3)oDw1*&uu6o@ zHe|KbKTyO0Ac?&(_|$|#Livp`EbbeTjCQ#plonZuAs98<70Acg5NG#kA7I?L<<5EI|tTb_zgSl|Y7k$fi`Y=p8BACN;quwC? z#Tqu5-Lu8rNY<}aq+%^Ok%?^0-S${=OXUZHNJs%J$8B%Ui@C+K%k_}U9K^ZF%#zmC zrody0i5B$cTcIZX_C&heTL@9f^k*j4mTf&7`Y@#dou*i6Jk)#m;p3tmuVhIW!{ab3 z4vXa0?>W#c5>GXbXs1r`_b(+WoEZ7=2J`{HNGeYR6HYI=jf>R=Vv@3ec3Mt*>eVs% z#ll&a4sSG@e~fEtIu3G7D9+>%Xh*3Vvn|N&)ITmo<0teNbiNpW#m=EaxBr7Ptoi(n z%lgcoJ3{Z3s@++1u$1dw+hrxyf3Xu=g&h-9r3XS8bATLb@YLD#z3UYp3|ho-!~(Sl%Z>Z6ZxTXfF&I@tRQzx< zqFm7Vu)v9bYb*Ln@t}m`ILcw*%Lyo(%oFJKV^ZWWZ_Wh43jq*4PUP&csmq};4O#l$vs|3--R|Gv? z`GS2!RGwkZcjV}!y22*u)T-7 zI|?aou?qeNzv!VGzV&y^4RqeK?qR(~o2plkins2rXUJ3+rA{K-shEeAhnddc1sGrW ze(fabQT4Lh*fO>tjQVC~;A%;Yb8#*v!bFR7GW=>1Z^>qvF%G7`+$h7YuHg*<9eO-* zZ#d0xcIDBmO`DH?2VpPaSC=BEp@Ip{L#Exevuz`iDvE+8_*h%m zI_(j&M?urvMYY^x8Uhgq(dAZ9$wzFcOs*~iQlY6Fac;(fW4S{) z6GR-g?NTWuLo1h8d6gXY^k%&gc)|4YwBVUN0<_M^jAA7YFS8sfvX-+r&a0L&ksb1< zgfnWig2Te!El&#CH9YkRnAQiEyclXo7OQz2S-7cB+@%Kvs}h{1UuxNYeH;GuIGf-^ zMz=P$xXP(K!E6Bk%jc_=2Oy{L{_Yo0w@((YpNe0othXL=dd|P7_HD5&Ll*Y^0fve| zPOD_-&^1HG?jBuNwMg5XIz1h_z_mg>?p)(XV_N`S)qxw=yu$d!N;^fj*K2nd+bvb` z4%&*+Ib5%?1ifEjOgfwbsji-3THL2yl%Jf&+Kb0ooGHx?YK4nRn85&oWxMk!5b!R> zaUi+X2byf#SVdEX0-;hk;dRUqeO&VmI8si~@BMr7DqT&vF%b>S29JTtI%JhaQAb{@ zEvrAVx`BBGFRhF{@<_KK2CnPKxtn#Z!{cmBDTc}Q0a#CZ{xvWiZYla2DvP1IAWvpc(mKx9}Iehm@P#y!|(`P#d zSmZNK$o<2Qjus`kto93Bc)Vc&nF%(Nl3(*b&w|!d@?-0An|k|3sZs^fCOEQlh7))mD;1(i>VfC=|-4Z5UJ+^$8osI(Nre$)4JygU9~p2UuM-h z=xM{SEL8~-m4(=IBB_UjBS+j_h8w`7Rka^ojWbDLR5fNe!QaGaWk^256|EdZyt`TyJFHQMNT4}Y^!?=#$ z{5SwP?e1D!;_5qCr*xFjknlK9I#wOKv|FAoRrhe?K9n6uZz0KRe@-S=>+&*r`|$D8 z^iZzF72onGH*B4`p1B%9%+xbK9`FX|aXzbaXp!2?%F^5WfQreQ6biwe9s+@zrRIGo!rU_{NK(}Rs zo-sKdUz0s7c-B$djqR6J;t-2G&dN}cX#bPhJ<#E0iO}seHoBYRBR=ifG}ZOutlk)# zsff0a;%}=X7{rwfFS&Za3m<%t*4Oi3a6~!Nw|3=n$%Jx z6D+=jXr;TZP~($Q|HgDwG&!=>;5N0k6T-2obi%A%9(8!g>4(FDfekjsir!1>%w`Cl ze*fbaPT*)V#AJlCug`@m(*VVhK=0o;L|3c+Yw1eeSSG3O$4|lj#e{y|NfVQ=>n^N3 zOvGG`xk)jI6&H$wsCej}C$G)m1%h;@8Oy&5vK23jK(aM;#o#dXq4~Qhu}BjYulH1P zqT|tI{waMwL%Tj^x|@#F`6y1{h6{C$#9HMLBKiQCR|l4^Wk ztW2v4=Z}*fqUcFJW1(@pagUGc=9qR1b0ciEwjq{;1i6MHuQ|Gk-Azc9CXEgNo=6Fr z&wNz|Mm*#Kr>oiEW=CN-_ziDykot)+PHglY$En-Hqx-lkk|Hec9tNB&vZqQ{L9? zxAd|@*Tg+WghKG`=wGd?x4Vg(YDFzb7M)js#d)Kt&Ci;i7Ni{%y-@o4K4vFcq`6sC5Nb%!K1%<|l3fiJ zr;VmIIlH+G{6)9is7GBn9pOeupp@@tD;#dPw0uh$l%WNu`=Zq#8Qzb_Q(%Ztq}8!| zGD$(cKQMm=Mur&U2RhYZ)^zHSc3jrbskX+B&z@E+=m16yT=rwFwc9%7X6w(wS`UBE zMCiexwH#23v^f#hFeHRVsAr8O4YdLkL~_w4!wFu68!YU}n<_pkyAIZ*W;+d-Hif$b z9xZk`Ii-oou%6u_WYGnY(^37a&rrd?W`%2bX;X2)Kfe1^!LEK zknbHWoc+)%yVCi05fv9Oc?7vwo-HUVSgvve>e-$3WCp}c|3lF>mgLhboe$xs3 zj}ZEkJbH83BZ6m<(}#@R-FjLpHMrfSbV&!AoMa7q3oQ(R;5*%`x7T;@1$S6K_@(3B zT}q;5-BuyrEMuH9bFYML7cV*)NaiVz-fLVu8psFdPwmmyX{%n`iq28b@n1j9RaoO6bcon?y`HD>bs5C{-oODt&pov| z1#^+k8=IY!g#{$#m3I$Qg2uuuI)?D%N5F|T;^ec!VevN`QX;od84XUWeEG?GB@;V2rZ zzuwuCq4A_MPcUCro~T9^Z!aP@N1l)OOt^&`p8Q%sW^p{PjTFAZiBeueOLJNc(OF+0 zL1GHVADmcUCscU4y`XGfy&)`Z@=fwq^1k1br_X~^Y)zeolU0oLe z3*&f4zO7|PiHk18l=ly;8?*(U9Sm+$m^fI+xzl}fWR!?E zDLGHv+@;v<%GTQNm3ZE+ynpjaBQ+WvS%qb9_;l44*pTL)(t7Ey?Y4A-1TXg@56(roZs#q$gO?^w_t$?j4o@S5YAuqCvuuKVoCn%A%RJK0=-G+$fm(fv)n2M~ML zUOeasSXo-*h7xUsHy^DZOpJwtPO}4>*2t?&ty!P@zI&aeQ!+d|)^S=R4Fykg%{eaG zs+?rUJOd7F|3e&Ga7JpF8dcv2;rR6N0O!#HB{LvS}fGi;v z30LX=>^TjOUq-49-v`3T;2n&=zu|Zb=05+`aSx&1p? zAdh?fc+1KEAwY)@mvTng>3yQ=?nYkrguHIehoJvZG}<5AZ}dC*cUT0C)VI!>sb!rI zw##SGP1w83twuF0!vR^zeQ33J5AfyNe=Vp}t60$4*Xa2UH8kkxcdrL*)B0kK8`)R^ z>lE_WjDwxIk>Fyle{(y^^u{OPg(Zul4~>)}8okHSqs=k}aE2 z#`E^&#RwxqHizk(px)D#J9eWzC4Mo~P*0`z^__k^WMKxcVIa8V?xD0@PnYhetAD7m z7k3%S(0-l6sg{#w>{HG+_3SaG7kyCA%b-=nySUsdj4$e+A>}gd89yqQ>x@W!ga!v8 z-@I?Wjs|?Fcqc*(-Y{f}P{!COGhRJ>@~lhfYd`jH{LK1K1%#C47O#U|7bq9}#vgTm zRQtSZ^{``mHV;QVPJy(z>DMK(snt+bqxT2G_lkLn1yR|X3m#Zr&$|eNB>YrN?Eg`* zW0#{hVvPZS?eo*c8#K`dC!o3rAK(OI&>o)qWjx zU!@MmJ4(KrZ?nE_yIV(~M18%?TYKK#x$to0&cfzQ< zIer*tH6_6__-T}ub^sV@w|LDvB#5NR4L8qwjz%?H2jS4YTFtAs{JC3xBEQ{Sow`5i zc4uy#m80U1$vCg+e0tDWf7qZ2`8IBhKAON^qKLy1lJ58jbvuj!^lY>ESkr~>^pAd( zak1&U3?zI|!rHaWO1$%uR%3tjwwH6%B~$~N&azEpw;L}C!>L+m_ZK~VF(kT7qG2bN zHU1%hzQ%#wcJ#xL;4V$rUJtn3jj?~rrxsy0#KVOs)?FK{bC11BQ-cc<4dv#rc-&S; zQ_;o{+x5%$4~QVXuBWoc^Kzme%G!qjq@)=ZOboSN6UVB9Q9N!}+wm3ooQctLo>-Lb z+w}Jjl%2Tv?iQu3-lA^E&qVf(MJ@w%k?l}|9+(*Q%4bXR5P?hX1(!>=?z%1voW06w zIgev7VHM#AnVBj-SJpeeTg1#7z+qt)dLBw(YR-y3%INK$S`1m0Yq{uZ)!X#Hjga>^ zXYO9ZANa3n>4@60IkdUFHMrGW>}aIhJu=kDa=mhq6W)|7ZQOa*a#j)&C-3>g4jDpM zC&(kc?Q>AYf0lU$9?fpgP>sm>9Ua0!U}Dp^iGUn0_^Vwka3#)(M4?4j(i2ZX;5c)t zr2S@G>zpRv2uL^I2jf8B!K3T;QFpe$?VzKJae1wFO`-wA!;Oh$f!t#YU^D^pI>EfO zK25rHy1f(bp5jZOd0NdOlLUiUdx}=U$aAkMeO!d!u5#9j9MLZwpKuoGN0`>j?nJNrnNl3Mv2 zv|S~61fS^D8Kz`6&fm`hq)>L-9Q!;n+X`d&+hZQP;5S!x85x?Ta$A{9wA(?ppL(sG z3ANAcS&f!^1`vIC{mjcIA7%qF6Z(M&OYUl#ej%@8hc{d0Q!cMg6(q$s*F{c-p1^NR zl$Xk%#0(VQdfA0t>iz@9XGz66wAO5$EM=E3%H}K`{WyshJcJ?IMR~X2pTO6!`Mu5E zzu;^igwnL*CO+gQrk+@=3u$>C*$)#R**p87=>5e`PJcONGXzC1;(00mH^DUIBbmD5 z8S3bRSupms81n z&kvonyND85;oo6k3cG@=bW3g&X9L_Pt`f##0Jg@x^q;31ESTH{8+!&_=Y;uA}yU;qbP~3Sh+kw~OIhKd>8JEQt zz|f{#rbfko`9U-{6;Js;0mx;(_vXXr!Pl#w36tqY0V-7v?9*g3YtOR#tq}Km1jA_E z){0|iXO9%U-cxnnu77mG{gy#a?_L7e_J?9ZHW$>`Y4%hQ#meVmNX|X=8gGp~{vr2m z!%COk=dsTo7ao6Q{944o68#Y$7lLeDE(FlL!-Brq9OK)+yWO7=n`mwIJXgTbhuIrDli$Nk_A^1|y_;}a26Wd@ zG~L#GPCI}$d+BM&o29xCwcc(*QVv!Lm^B+C$pxJ%%@6`A3l6|Kom+?Qq2}*r?i*-L z7uC}ttl59MZtB*AVb*slCG1nJsb0mg2P_>*GRE&T{GY+5k)Amg^P!Nq4@EAn2!MV@qnBn3f>uEXlML&9e-gf$%_ zYygc#CqHs{65JjUw;<65C|o!8q_=8re$+7+e8FNFP;+MGlJ}i?hbQQ00fL=s?>O&C zm7Y)VTrZIcXJ5!4E${)vO4AIi{_ANj_pzXP+L-K9^IdUondrk)I%2|dm#^A!qzSf8 zUYRN8sT7ePNAB?Xuuw|{4G5oor6mdyI_r^F*Yx+QDS|lma@otd5?d!~yaDd)SBEeU za$Igi5(;YM7uTmdNKLisVDP??3S0@$0#q!{j{3Ol?w>3w#Xb*M0bFRwyr!1g`u%^H zd&{6Ww{2}SAwhx!2=4Cg?iSo3xVyVUaCi4$jRg;GA-KD{Hr_Zi(tNDF*Iwt`Key`E zsZ;ms>gulQ_pPou$DDJF@jOFbYd7j&%=TBV2aMdgT%9kA4=}0*1`xQ6^ zn*&QGQ+Rg$ESMRIF0VBbOK8s6fX-^G-;y@MTfuqug=->E^(cw)HvB%IdEdKxNDdvA zL-56yHrkIfJ^BlRUQ~;l4LM!7;_aGgX2n)ADm96H408EG@e9Yq!Taw=I6UP3qa}(L zlhaXGpx?Y4d^C`kc*w7Tv{HwIN`sadd6S7969>USX#$=ZKeR@ah{6c!xI3-8-%_r^ z8EMLjt6sAXIkIhDuypoad4rn#zq43?*FDfC!{MhuMXF2+@+zte8xVIOs*{jM0I;Uz zIP#4Allb(8TQXwpUBPP0^Nhn~A13y!hG};)_u`G`GT}a zzbwjt;A614K2bc;7VbX)n1LH`i!oE9A#<_+Z&Qd(_f>4Co>*!$LOQ9SX+$R`t3O-hu?Ah{^BC z#PW?WI|&%_5V{AZye>L8Zd{@bhYG{tSlN9C=Cx!7yiAtJ@q$Se1aHwLB|k~;O#C-P zbooWJJ;l3Gl;dc-jp>PZO!nkHs#;NL3cgovAp<6V?O} zc2BsVm#w(DzgH~>n4S{Sr>j)PZ><@;>S+(G_X)%^?38CiQdgNysQP$j$cuI}mdAW% zYn<*{9d>?#RjDOtaEw|Y>fTuELqZH~+X-Y(_3VK&rh;!s{jxxMe2n`Hit!UgTr1F@ z@L^)pd42-7A9Z|BEYvwbX13*s-gi@q=jjxI+r*u&Jn|ppH*+!)SibDfGgl}Pox$Zm zIGl$G?xul;z6JKJLb64Jhww!`(jSy|)e#Ryi`>-&L$*8%On@Fiq3K z%<#Oz%a~3|Jm+dK|1r~OW=eP^rJ=>50?Y0pS>~Od}mrUV@WxPon$m@L5E;zxI#j9DRn@o84`k@ ztiYRlG>$`q+DcvG@$^>vvLpi%Hd9nDD*u} zG}J-Vgha|C$o=T*y`QoiK6E`jiFAE1r;vCcHNN9(2R)g5zJWbl;Gx-^5aK5A{CD+e zeGI*TE8o8jmOswF&>$|5LM}ctk@C}#td>q%;@k;S`;1naO3mvtuBp`TBr z-LKD`xHX56cS6mun~kK`wiJ~oHF-2f8#PvZPrT-|Q|4;POKbz+NjkCJTf+| zlXn94_0bx~Sd-X|`}TIZ?T^K^5m*9Kjt#l87k-+*-09b&pz2Sn1B8h`ew~d$=~UUb z5Ze!pKv{eL&)&Y##XCKj__R#0ea^Vk!`crI>Xb zvUrf7e7+*y!(lnFq>Qtt7>PGtxhb;xd~r2+V;0g98L0|j0q`X7d{z3#yXiQVS}`*v znOrJo%iv@@Xe~Xr7zX5RD?8xeY1Wv%C^u*^I|#D*5Sb1)u{zy|hSxw#;tK>jfkU*D z&aZt%7YA-#-RukUL&zCF$JdU+Dd(l7nI}Q)VP=Kj)%zti*IFFvHW?6Oea2V8a_^>E zeF^I{Lwfad;ORm2`ezJMEt(#d=^}IdL3Kr|N1H7{^Q(^$F0BFu8t7&>_S*d;PDPm> zr{a0*ZCSY6p^7G%3pj@xBL@V*rcd-KW~gA}MDEH2(`6-z2rFx%{-Hb4`7+5)hXn7e z(vn7TMtD={)GI?X>US~OmNxKnNfEv&N`&;PlXni9Ids!2c~n@e*8A^aY^K&$#I1lJtoYUPela1qbmpJwIUU3ZfX-L+9m9=`c=~H zS5iD{{WIKvBDSoQ4_m0O+%Jc{wD-z!#-KZY2A0!R|*FyLA#2Z-2m zFW-@nVo|BJn}|XcyTQoyU4Ss-T3{7VR_e@r9NS}Jp;8% zn*FX^+Y|cUJVW}TG-&v6EymHXW6XJ8t@eUsfn;a%cQjfo%sX+@jIj7W$|s4OKudqUfFLm8bG_FYuC|OzhRYSyie`>{z2 z?hm&casVMm+yS>zK69e-s^+Y!^d}}yQ*FsCwQ{wJCn^)=ZAW#|kQnb)8Q#K3fG$<% zdTh!2buT$BD1*Ze(q1*wv2r|AFEtf`fCOL zKra__XEmRJIQi_QWlb_JXI!fB?1{rP{HL{;b4O^jKj*Md&jP2{yeLr97phiS3E~pk zd@DnXkB7L3F}Q45i39|HeJPV^4-NLp!hX(MfhO)lkG6Alb!GOpg$>mv(wmPFmTc86 zAOuDxv+jFeb&%H6OAS6m#?V5~&@0&<8IBEcUMWjv?c)eIL6N~T)&7@ja#NAu!=T0* z^2TodG??yBLt^;#3;okP{7di$wF;aP7J)Gyf6iS=`Q4TyH%y_1urB)N94iVon07vC zYq!sGi%_5T0~wQk!b|_Dp1^HHoLM2(%N1Y;8XLnLu65-WSEY&yN@*XNXc`FZ3 z?E$)IqfAm~LLY6>+PbvYeMH-fz6{O%Jz}>;Nu`UU)$>WPBx`+Jan0t)dcRQ~~{Oo60kt7ujz(88Vk=6r>xgRuf71q75?nL3Cmwd=)Vk}_Fh~{Sjao+61kT~-Vu7) z!}a8(y!7n9Vm*I} zpm;Ik&6PmFq$eI_{ma`Bl_^QeCH{M;H7rQTXOgkF`x^hmWM)pX?*H%hj{jHvL+99P z;YMvYy08D*KArIB@NZD1f$U9?xIeZF*6+?%-(>qH<-ab^8IF&S&slTui6)VkzsDt9 z2}Ow@wKz)o>nKQD|3ZNx`S|Zka-;wH>0it7zZ=T>pS!oC1d*}uBq(>_S485`Fo9Xwn2 zzj|)~-QhY;ZE}MR*g9GBE4|P3#d@#rtFYY81-I6^OLMkg*hcn;rD*1@uY&Fu-$Gqi zELvGgLTil`H}D2%(E6D!XFb)C`YJr#3GR}6Zw5lXjOxhW4PIG}F^pYWn*ZW$6^ad_ z$n1;t(&mmpM@AN!TztIYgnFI9YASHsp_oa^IEN+{n#g?Nqf7I%lfn#S;*-eN`oFnI zu0s8*pHK5IDx1#>GZ2_6V@XVJ-0!E>H7S>yl}QrRAD5TcCxtnD0?&~8lvAY~T7$U! zFR6Z>BK5)QF!rH85t@zQ1dPPHi|-k13s7msv^+KBA0WN{3T#0+vr^<;Qna`yK6)P; zDJrVy!PGgARi}sShVpUA5yaK9)u35doFwG=RI(V1@`JN>v(>@Ef@%Fly&lU;H-wtB zD(&c;kk-axQHjUOlLn|H{Uno2EAWJ0%E#+-cuc3d+fQhKvkwt;KVvMdjE7iDqC-RB z+4Eq4J#Ee9b6@b=I#uN_P|%)_#lLH-I>l zk=I`^te2yoAgG1H8Z|Skv+a`{%Awkr`givk>6;S~mWF7Wez!Fbl|)PhOe;RRVcdl_ zmoLu&-2oKHHALj%gr0AQW`?O3m1Bmn4^^Nt{W?|XNzs2sFt*jiWsWZR^kOH;J%VuA54Y}L`=ddOTnIu!w-hHtq3vv-};in>$2r)@P17la&yo}DX zO%J?cD@jaJ=ciw09(W~W2l%-A<$~9G2L|;~T#yl0NfnD9&GGW%4G*WF?qCE;uH^St zZ62HPI~mln2Qdu6J)|xb~bmhNnX+zYKabJ=BI5RWTp#jjuC#F7Gf~n0l&reVqi; z<2~Xdy|GfEFV)%4_SJA?Fo~#vOhjv+FvZ z)M;0c+-ypU@IremEMY*LQv=ZDPYQn}s5{&dGWf9Y>W5ZzqJAvCx3gVR@9JrQ+vbl~ zjf-fIPUK0D5o-D1&4mYvaXdL82Ci@$pA_9+EC;lt>Z!&XIU^u`Mx0vZ&y3ggMFnMW z#iilz-aMc6fe+1_{mtiEQWO)jDRbDCnSFelPK+P{voB=uJcS8~ zr(Kj$;nk60Bg>rzAORl`SRwU1;8fztmxZ)`kBdm;&e+Kg z4?(*|*6f9 z{5VdCHZom$O%cC4Yl%GG5~n*R8i1W;YO#N$r1D#HrJN<qgfrD6*`hXmtk9CUicWVvQ_hKHKt-cp)NS?eeiTWvnXSDhA^iRb0wc_@8;qochD z2R-`KV0^UdTq!2)nN%}85$76S!u-vp|75Uj41p9NteQeg!fsum~#yv5pd)C1} z^}51JPWYsw&e#{BLQ%pX?`e;AGfOoatYw+Bs{4wqW_kRNv9lf*E*naMV;qhw%q-&G z_(59xU^ooWBxK`>QzNIHJ!G%mR3Rrvm9H7!1O}G^b>;ync(r(dz?4T*)Iv`y$Y=E`}BT z5)c6U)W-$ic!6WSxW+FP76wzr70G9-E zT9&&dtsIuB*jVKC(SVl=5*YKIkQtU6`}0EAxBipZsYQZIy)zhi5tMRf1H~HN3-rK1 zR*OrX|KtMfua*BNQ%Y(LL^Rg+3!u5 z&1QTX_B?K-+;|u$qM2h8t;)7Y`$?ARNbfSxh*I|iixKGghvs?t6@sCVJtL=$W4Pbz zan)aWzMq(xoWa9yBLSy$wAw#op>eJ25Xx?UP__$n8p#MLJ?~Bj>2>FoTP#E>j9oWS zm>uiscwN+`<~To3hg8{kS?_CjTjNxjP_cPTs8M1)YCYe0!(@@QEu0r}n|(%m zv<7jyr?|-FaivQO(0Tg4ymMOpsF3A@zN@_k>lWei*7HD-H+b@OnlD3$QL5F4&O_G= z5%AmYpVNAPlnfyU#YT!?kpCQ z*s=vP!}Z~WTboSXamC9|DHb=)=toHS*@vRr+xG3 zQ@q_d8Q(8S+q5a}ZYAoXi3I7O)r( z&Zg5;o}{qV^`$asyZe+^2|NsNN9C#_EN(HdPFJCmI}pQ)1@`C=8Houh5b4Atp&<1uJ;5eP2$`s;;7FyJVc zo-pE2w=={+&znop)qD@O+4)RyL1j{EuMk%j^onEf03qcqg1XIpt9YE@^K?9W=UTJ1 z2|0uB^4`UL{E`DJCsiC1b08|GWv$^zIl^&uwJdh24Ck1gA>n+FJ7f;|=Iydwe7<@4o7U0?#weA>dl_928{*|FY(>O5poc;O0uDkojc2 z+MEO+CHU7US>46ys;U^+IXGt3^m~Y2&Kmi75{TLc);qH3x;%s`+bcp2f2$a0MX`W& z#p@b#GhGgxB)ih>IzOn1z2#T^e&iX>xyw3ZC@ zrG2Ri6|8=tLa5Pijq+D2 zHjg8q{JyF*;0YeGRVid7mPK{8F+!jj5O44VvN$S-NxGtBe3?*e@c>KO zKQ17HS30x5?tDqTy}xcw-yE%X?)!b*|Ga4CadlYDTT&L^Ufq^xL%8ylC!qreL_&uFi12C%Vw%Fs=87H#@_Nz)xNFp(BUfp1v=|Zh2UJrpr_4 zWVhrc+{UD(iski%K75KB_t;$IrPrI??w@zF(GFs}a+x-2LnbzPBN5`d;%(AWTeo8P zC+(KUlA3TjPRi7&6fQNCd^x6&d%#sbY4AlX?+!N_+es*cUhgfHcc=@ zwfX?@AlfS11j|BzM`RJOoXLgc$ljA$!Dp)4>0rt|bErvd`q!{Z`m1K1?_oAabIW!{6m;1!(3#Q% z+)1DnR?c8q<@r_~lEZQ zlY{Q~GH5h09zMr)#Hr&b=Lo$m`uXtS#M4}sDR?yPYL12KYThGnysqRud^XWmezR0a z7t)&3q%olDrB~N?gZ-*g6>ha_GFP$6XuDkE$|_R})RBNZVdKP$O^_%WfwOeM9&jgR zP)ITQ7AmQ)+m-9`gm}t;H8z~Q2NctUWPw4dmIl}4&1%5w+u7Bxvnx|q$|Fr?cuR9E z@w1dtYP1|G--{J^gpyn)aR!Ap+Okgn9N{lE#1QbE+}H-BjYwOtl-S_dj8ZABZ%BY! zif{xTd9vz5G97$BIAp^Qh7v;dR;q5gd=g4DHwNO81^YD_^CTk$DenvhHaEHwJti}R zyXHoMXb`|l?WHQXd6aJ<5pfoyaaCXNX#0b*%SY)SNo$&FSscf1)%bstZR6N|8k%zmxx%^Ft;{vN`+G{ZanCA zjCCa{sNcN5!issJM-0{tat5l|#dL^CMUcW~Bj8ST86A>Ne?K0z)EcRXeD)gvZ#>Pu z!9xeWS#yT(#1z!1iw*aXuiw^=?d|NnN#nTeF=om_S+4ij#%)}-;$p6%Ww3>$|KFes?h7r$z9uW9h_4=q!wk~ zBFHQ~9TwS6*zJurS6R3Vm-KK9yn5Rbouu3UwqnaD)13&n&yVM0>Fccs_G++MZgFCq zC{*aW(L77>J@)IUG7P#IvLZY~a2^a&!N=qw(P{fu^0k+vH9X(}sDE_|pQ#r0O@ZRx zw=DF^n2+e&{_bqH!bNkmP9##CqxH~WBNs-p2`U^}JM6tUw|M?r3k2v^O8`q_PD!BA zt&)Mh%=yIooBIi)#(k_)JT_|F=!78}fU{?avfdz@f6VNL^SPyS!z~XTLONHSku=4T zcktk=5fznGQOI4>^g?aStLOa}+FTs#_3i@%zRz{m5Ye>-M3YpThljIqY%wbEbQehl zs3o!4;io9QmEnGEB*KSY=3xixJv+Q~abtUUq~sD4F!pLtv~C zNoT-E#ebt~ZqSF*4Mk6*SLvQcCM!)Dx7K+Lof^(~n&tB+A|m=*V-9F*H#(wahTVtE*C?JGNh9 zKgxopet$GcgU5Wz#cqpSO;>c$N`lnQia(*DkJXTW7a2G&{P8PfMp~)27hn2!!|VNP zEi{^H;6?%QT4!91!dbtEzb_poRnvCo^ZH_dsKrv>6q;*$_25_>W75fO0?>uj70n~= zL(LbeL{@D6Di#|j!PdhqT62lSf%9uzpFiwV&kbPD>zbvGqUd|}l#87}{Q=Etz)I$yre?G$h{Ds2ftd zA7_s^A&VLN<`g8vQZ#gYLnP?W6O*tbj7JKAE0IH|_`Rl$RYAjS+N;*~f zSvgR_*7&=8_u2q3KxLxno>Qg4lTpaGK6>KXW1tcL&qg=>eT@&0wQDk9bx5oFC=Jgsl_rr=Zx=wWrx|PBr*= zywPWNPmkrU$D%h4mv@5@6W|q@wWq#&DWX=aN^k!Z<;N{{^^z^2W6P%n&v(2m;A!bw zk>uu>K9R*=Cg0ygORH~EEqd>L;$nWp#44|?4g`{uU1Ir*&B7}tJxbI}(* z&C$4b_=Xs)z2^IZEf}6b-A~M1<;$IMh;QdDX*PE|)4@Mnkq{}FQ(ghNv_%%n5Eq-Y zovVh01KR}v_#yW~CHJAx7y5o8AhBKWforYa8P#K>BMAvfA0NP&Uz(0K`&+v`CBC!f zQ!@soLjKO8V#g3!d(=b2Nmk4C9jpENuk672>%)_yf;uw+XhH;0Y+zi0WlJH`Ri5J6 zV3GN~NN(-k<)x4xR^_n^wveTp2y7BFyZc(*s{;J9tT5;-7>v&K=w=Q>Tpl_CoW} zv~A_ab$rtBB(S)}nxiPi1a2Mo>o#TAt6#$hJ^fEKy6)%nM>d+%%($3{U$AtR(DI@k zJikvw!EdPMWZO~6%|{{{B`E*21jyj{Q}STu zs$ZN~TPo0*!h+EYDOZcHSD@$fNX+VPBLbqf^7opxu&Uga)i*mHfdwrzm(=)*rYLNb zme~){S!J#`#qxX-Ui!9vyM0J#uc@uy5{v8Z4ydIDP9{AS!H?r6~M8b^l(0}ikj?=h1j3>8P8+N^XYBic+kdR z{@A$DVWw0Iu*U`1SoXt;)W;tXKA!QYB_fi5f~Di6LL3ro2GSi?BwXp8_z-)_m${Qn z#MloI)rMn@!|i%#MZUbWiB@t8EHq7jKybtVZTQ&F<_3ipifF9unPe4M;OK7RK>~o5 z%vk1D68>RoaXwTp)+YMtV-r5tEz1{EUI_)N#>NYR{^LXXH;skgxF&2=cjtvw zV%vF&YR1RF5h^3=6i)PHF7NNXXk2v@RS7H&;I+aM%S{$>|6A`0DE-HgwO{vyrXJ0? zIvaV4y+1Ue4A#ermvC0tWakY(-8&D1@H(8MQZ0L~>U=$BZMdihQ~!0+I5!rk~PO zDB2zdyZydTTe(4*t$bMta+#d6)f*JoyndKv3P@dTTUok!9(~^G3fScW`7+(F^ZJ+* zNP9=mrb$x@3CrqHv~ogMl_bsNAO^flp|%~U)w%AjTKaCG`q!1hJ$BIRX@_dEvBYE! ze&s#5Zk${jO0uScXY3Hfa(6|PV21go7WyF0wE6mHm)gTG!~)V7x^qKv?l~DeJ7OP- zuz`_Xk)EF`Qe~=|E-NNaF%ITbvY7s6NcC8w z!!tE6dN$MOTW^lg?OC6jo&15`t|e|n7uw}m{$rqI-m0uuMKI)RPAG<8$|=mTW#18E z9GkXQxR^`*#p4(MIyWIIpu`1Mm7&`ykN+G?#C|JWBdB7)hH(5mk!m9JOpcJ5&GE^= zH>zfH?z=39h;k3R@=RyPPsRODs)p8tZ~i$~_99}P%^+dk^Zd(LfUkh!%e4yozODPn zLAvZ*VF*e@d0Qs)J0r1kod4u9IQ*o$N#z!i@;jqsni6a&EK97DTQ#MYlUwCH|OtMaY63uY3ro`{=k z-~2fFR?pojb(Z*(pS{mlrFJ*_<3=LHu-Kj9#D8qRboOzQ(6y;~Se5h9W(3Zo_ zByczX91QH<&ddwQa5E^yaO;Kpe5KtQLQpzZYvhe=F69+M&e!WfcP18Y zo1wuDBTi-+I^-Sp3_0)m6g0t~^QSK{eeg8Y-u?O9%AFfnTktzbuxeL71Lk~yqN9dl zs2k!el)L*W2`5;MUuLra2;R}>^H^IEW>ko}zCN^C9R=-#{_?ha$R0ghg1}3K<|qBp zWp^=8pUza7t9{T~Kis;wGr5s;yD<$Zs`+)P;&HgMpF*w|2v%c}XKfQ%Vg6c@gm|B0 zF5bN3PJ6gOTCMX<4!EoHuzUoiQSj+k%cTP1MAI-eUTH^iC}?|I zMm|i5@0lbf@M>%WJ)e*nu5oEp&|C=w6b65DORJ9BCtF}+hXqVNX#tJ(+)dE zpZ;@58_+J?K95ON#bj^?))I$qS(6JnXLO^s#454uv|k+T|BF-up(ns zUisTZVWz7&cJ~s!O=$`pB`nS;%IcOUu(oxG>BgzeBXGlQ|Ql)zTkY~$foTU5fJ!TW4mt_S*FGb%ktQd6PeKY!8 zEa0Hdoy&!5O0j){%)p_5YXVRo$LNIv!}BaCr!5p)%A>vt`3fQ0()Nn2&V?vD=shL} z&`{S_rXD3D4u1sRct1s!X6~_TE z@!J$;K2dCR1(VS4#><~PY?!N%e2o1vrsb=T+Lj~qx7wv~A;=4jAox~&&x<|-5P9r6 z?R^H{^lVHdMln2dUXQyBHoDh`I(+x7`xV3iyJ>9#h#Yd@V=NXyWGUp?fQ^xQbi_9 zoPTT-7N+IwgM&$v>L9ZK`+~X~ILvy=X8^w4<&d?~SDg820$Om?t2ol!)YK{?Y zv0o?|e9D7kGXJ#M4{Nb1jT;oD!qimF2xH?wZZJQEV57vx$>#O)1^xxsoL$V3)vxIk z4Io0ANs`=Dd$`WU0y>$zY78IH+QPRO4g93Nap``5A;z00ntXC5t;rlnys_RtJ85fH z_Ekc$gxl+odckI~u8jtk4N1N7K>6tc*|M@bd*17Zg*l{iUhnse*2VR!cZg~O9rbwN z#gLW$vDNlDa05GoFLCbopXX;&g_~sHky(TS!uKP00vFy^rW*nHV1V z4vuTDI9wo&d6z%Q4Px-84^j%KHncmo{#RCG+ISzzbr;Y}mfPHz=&)L8TtC+xmFJ?T z{uG^`6<48z`J4qD+kf<1eE^&AA|PN9?dg^OdPcOCvbAHv5*uCNK9vxAngSzY7o+bP9>VHz`7rxhETRhyK z9tQi?PQ^9pYy3(P*G&o_g(* zLytNXmTyQD`PDUNO6V2m-1Dz+z; zOEwi9WQV4P-xiOl>h{aq9ig7YmvdQdryZ`Nb^fQ7h4%-&7LjFksW|+Cl9GLSq~C9^ zRtkH_QnWJq%rr_aK`tWsB*UPklXuzA>f*NFpJBMytOy^k15B@1Ca=!;;8Cnx22}X5 zX~KLI9c`Hf8b88Wa&nb4RFu;>7vfSz0lwfJ?QTVqP`Y81Hh&LmQ-NQng~Je7>5UGj zqN%DbDVX~#6P6czh6s)OP1&A`2M2I1j{K6y9@RT|3VoaM4Z2)Br8;^2M!uLCozDy@ z_80mpiUr>f40ej)Kmn>+uJM9?I_$HPBC=y+Wxw~BiNz;hxg@O^kR;r14&lQ26xeX* z>$v^q=G0YCYl{*KKo2x4utndTJ3cy}71ya6=!I-1Zi}xvwFOCs^h^FIj7noAQeYd3 z>+Dtg#i_cDVgXyD7A*}7By$a$`Q{97nU^YiabpFO6iT082^&YbqYTq&c&yQ zJ!YUCPKH`iS(Ln?1kX?tgUc|K;D#xCydH5aIe;#Kg7n#?j7(I*1;flAc0_Ggd3qM{ z&V7~zo5aM@Q-)S+O6@x?Ay6F1oj2kv^TH`kInWclzBkuAm5~f6tqfNUMn$w?#K2%I zGz!fckbyEzLZfOsB8(+tr=plwpG)_u>wokDTSgp1$D&sZDG(mP`;wMLL?+wv;fkPI z@Up6(=DizdNJanlQM3^Sv^J{Q?eX1=$P0FHao@Qv(RRKNmEiEea*{jQ>Vq0xYv7jy zcJv*UvD5nWVU$6|JLdB$BP|I=bKa4<7d^`oj5$r1S_vP|OUt0N68Q&=lcFE2v;thjLLx+^MCk7U)J%@aj8O+k9ivR5OWI!eyYr~BdmU)ta z!gwMM0^<!2nthPs?@5#qA4nMVY< zp7f&h%>o2j8Ag;lQX67ZLP5J7H=JIosi|kW=dn5PTXdHyR2g^yXsq8Fs`4@*0y5XT ze;1Z#0GvdKIxDPH2ftXtoyuSzB|W0cD=D8 z2=f2La`rIN>Y~`6&5R`H1mQ4Gk7b!eUc5QctiRX64#TfauHMt9rC;%i4=ZPtp~kI1 zH6LXnIGc9H^jPvwJFP?c@jItuw ztP~?`^;Cud(`>f}6Fz{lim0Fr8Bmhz<*$m05s8r%+xC8|;1AspntQw9eIm$F?k`@q z8`=3tK=ZJ9@oMH74YX5}0KkeCp0bTaT`Fs%ISbnJ zQ2A34fAzbW=zuLg?iw8Mif$u7iL+ZMHT+rbB`*=jD2r`_F%Rc6+DpfN(3sVBn;JJ0 z4&?d|*9+et_UY1azX30~7+Jkt3fO$c+f3nZ@ue|MoT02ssz2gf01k}+P-B;OPS^3v zmz|CmB0xS!z4}#UyUkQrW+qiFLZ3gMCQ63XIjP3)^n_ozIqwxTd7yfvQBP1%Qxwx- zsgDLF#>J?wuUpLD?#c7AGJ^5;&={S?X(o+DWo0Ubi=uq~q0P>W$(L7mJoP9Dty`+* zC=*aXCzKn+ZM-PXB#-W!Z)2h<&?NfP&iA|C z7Hso$a(C6h3;9}ipmM>hk7z26*@82R@h4esdRJ+H|7C}d5l+AxfntT5ju>qO$1dML zHyfe?6IM`k2*5v0`wzSt#^9P&5D4&I^Gdg=)2_9Km!x#*QBi)wUYhVEeJ8X!7;oHW zimY#$af6m}Xkazo^0L!g5s-b2$JCbk32#)?ym3$Ar<-32k_W0)j2gbjFu|4g#fP_oT>8<3CQ8)b9|H1PJ`@#&3kwS~ z)st#7eXL!!{RkDfs0*R`^6AfZZH)L)RG}3vG&FP#j}UpXv}i#>jPMZ>@cyZ8_3Vm= z@n4FLTyF-0&C&zVusu~E#?Hkxx<5@W-9}qpF)}rUQui&Ut*vcwj^u|GE}zG_X-^Pz zJz{DxS0ca)U%)#BgH9tMIr$nEsQPBIN@q{k+tU{oG%^)Sq5)Ou`reVN4&4NLiw3F! z-j0q5hRk23r6YBDRoaZNde7I}Tdybh3|#!N@$iajYT~1!;4_JexqilNtgp-K=@C#+ zP&ogm{aITvoi!jAB`7KBOB%fvDd^|h!c@h@eSVv_z6THOsFJkzb!>cm_j&jD8|tqs=K^Aa$rCbCvpa3x1;1mU)8^?s>%%V3}*dO!WC0U?OgkJQ?|#>Il8l; zz3hY}a=kNC9%^Y#cfnKw|CwxwiH#I;t^6d@tiQ4NhIT~^)W7BS|M>K_8UFid|INPt zebqbqfB*OPW*O%MfytMwP63mQZcycJ>C*Ex=qefbnK`TF&yG=jbd{oD&vwC(88&xv zpg{LdGoM0|f2xB-y!~#E6mqgRTTsH0#Zz*8odq={t?&2HLH_mB-H)-FnSH9a^f^M` zn7bv=tM$Vnr~hLx(Zz$T3F`*=k$UX)i_j~!kU$El%P}-$w~OelZ4zUV#3R`!Nd^1e zQ3J20N4spih!Z7g@FdC(? zSbl_3OFxN^pPAP5Jd6Z>!rUCr-(OsmIdF=?*CpETrFy(aO@3A7jrhkczD~Y;HT{tWM?l zzU6o<#UEJ%wNeW);3`AjTPn}P0{ z&-a*kbj`>r+%oFkEvU=Jo}J;|9FkOgikUP*6jovxQcR>0s#v}p0tA{NXsT()$^jvo zwGTxPHZ*;`q}%TJ^o$Uq!7W(w%1DZ6AutJrvy{kk-@UuN#KeE%5fu8dho`4e;6}wK zfQG`NSkNQLm6614iQnfCM8+FB>qAIY2dh&H%YJ1M05mS<%sj<}aGWONMa0 zj2BpMs7}GyjZ(3r1CnrhY{q`euyTEoc%UA4n@EkZn3yoSJG!r}TNGo(Gpei!>}28} zohx&58hi1^L`08+8xm$=Ee@DVko%gQVC)`MdYBGR2TMNqAOR~CLqLuPuyop*Ru6~Zi^X0Xb}Is-os_^T-Ijb35-<%=09gxY0{mz3+k9UiBqp`T{mi1lphuh=jT2 zq{+;NCKd=+iHs0_K*96bJ6P2Hbmi-)gnf{`w)ohsQF^YlPG*`UDm-*JrAv@$znXm1 zR9<{Ua9AOt1XVa*t8$8m@rY+rD%Y@Gb5{Q0zFU3mT68hsz-Dz~ER?s5M(g`j{*QW`(-;=B{}SEe7Bc2A{H?RX4+$eJUu;+dKG*he#sE*ur5rkGm7%q=h^!XE4&0VZDD zX1D|(4HkgbN1DwHtDLx#uKHk6E+jkV(%~k9rH@KrY4+R<>70l;oz8?C$xA~wInfnl zKnWWYG~@l@fe`e~8I3?6)UbNkkks&$?1BlhEEEbPTz_Vr>iDsfYy~oiiO$1L-2VC1 z)G?q=9$L@gy(~hZ;a4&m1ms9kgL3sbxcm{!hy@v4-*-P%-m{7fiKV4V2buzaC|hH7 zdB#GBQFyz*6oVA8uOi?btXSdnI{U0W3{&@(YK%Lc-<2dZlsZfEf5S>*tHGd&xO(28 zkN-^)4geBzJMNyaX~6pTZ|k3}wWg?W0bsnixiu%tXBF<8qgiX{VUQ*llM>6Ei-w&) zy`m|WVcOW(m|a7DFE6LpZn>z3FCiu_s^FJ6K7vPXzIE*Hu)I21fd`9Avq&{j)3CS8 z7$V-G-QC?N*0#Djv{>=x$p7k5OJ_&Kjcm?0P%WcAEhj4*8g?3V1f0r095hHVb_RZ{ z9YmEw@gY-E4b6Ph(%`9qXnLbwb6T+m&@86U$MtvtRat!MVOW9khG)o3)_fJT~uo259d<(`y z7#x}A9R%6EBhfTJ{Mi$WPC#YJVD?z9>S$ErzP}_+ohBH{XO(_A zsU#A)o{QGKjW`yG1yKJce0E*|%{ zg;AGA?3Fa|1e)wzSBD&Ixg}l4(EYsDoZNQ+Ycth79M+loeQ7L!Rq)kIcT0U(G@Gtp zU82PCk_Q{BEVYa)km{GDIi66-v*a$*Ua||v^5iZ~oB=E0r?O+*UW0%xh|Dx%*YiU$ z_p6al0dskJg)HO82SNWS4kQHU!0Px-f+Lc7@9lwDHaPi*+HNA}1$?8+ zv8uprnOxSZ$3nRZ-$f7PKgzzRPW2K0sj?Yk(u9f#Z}ath1JlJ-7r8S^Xzj!Ga1)*M zT~49Vd~XL9fqJv`rwW{fcma>pE(fB8vl4?D&1#K?_@rZ1c@vVN8b3r#q)3jyv#hc7 zBn0Z8Q4TN5?>2sYsMKgmcd5|2JW?=hgD}M(R2%8|G^Ww%`Kc(}R~BV_jdut?wSUc% zscY5~dkKr#^92^t!%3st^#k2vW$t3mmOIE|r#NCEeQ4au$x zoK&Utvwm--#NDAIvuSM9zU`Wtsfmq`RZRMwClghlE`B<=CT>7yYHML!RonY+Tr+!$ zaeWY6{05I|jn+tg5`nrp-nP0HNlZQ~--v=x-AS=`!Ye@Xxx9?tF|Qn(T_sS0*K1X& zu~K&`-Ni~{Q9dmDGqVt2*{?6xrC&_7T78g%ZZwT+QOs}Wg`*v+*ureFgS8J3gZ5z< zagN_sUSt2ON`swysF>$LYVBN$H4>d_rQt+9ye!GGoE^J}pB(466>Zfj-QIdpncZTg zTv}sFPjlYvT+_gtz9_FODKv1BwSk(?~RWJ@3%|*!0~~Lo#^^SrLfT(-x4B{TzB#aYfPiT;6qHc8rNFNfZ+mj0^`v> zqsjV?qDHx{XyS`$GKc2!?Ji~W>GGgIc^0B5dxroDw*JksF0=^7@nVhXV>wb~wPc-} z91a9l1#ixN(eX-)=_fkQ$~?YB+11?e;8r`iO-1HcfbKGw zx8T}EwfEB&tk`trw()`$;VM=*KtVt3^m2onGn298D(jW{w323GitME?GI1zsGIX~$ z(;HUr0_yS{Sc4m=ua`@RNJrc$B2+bFrUV)W=6 zNhAZ)DB0tOl$1jN5Ms2U8VuJOEzTbhEKj45kkO^09b2k0Iy@@W+YRw578&xx<}#0n z2IZ~Qqj9+zDl|B{!@VP=yVaNiJG(ccY!+-PD`|@I_+(bYWyx3#8LhxpI~z~Xdx6(O zIXzW_af;BD=PTTW=t%W0>(9Y~OqVV!$})gwDh$m2w>g2#2WJjvs*I5h+R5^@_T+bfmBDme=GKX&z@OKV&EsWNY{%vejc zd**iD$0wLJkH=-Y4s>(l!8Xy-8LpXaCF{3|cj*v9a;yS}eVlPas#%dUtvPzK_8CdSBVdlLr8{wJ>N`Tg5q}_sLuXnEtFOIcGryBg^n@OubG6<4SoxZ(> zu+UG3Fo2h48@6W`zI@3)iB`&bxPmlpGb)@V4zl>zoxc_TEK%ml8LYyQ$Sut}LQUqH zNdC-Aqo*URpz!fjTr4$e$&iF!n!=5-snt)Pk5;wv3lAE(0JpTJvK49)c{h^J=7Qa!pbK}`)lksgPfzt2k9&cYDpW9utwL* zI=fGRSl*@_Gm=#qGNW7oaG8LX<=qDihM(T$KiQ~ne2e}=AXvaS;U}2FH;zYK#HUba&{Eq^*~8z6%5S4iwjgk;F4;6FK zfRt!nuWF=7JgO=J=@>ls3`nkb^rG|b44K%J;7psaog!N1+vd`$#B%Md$!%s+V)f2o zC`WBatfq?SeY3j=0_rqaRxr z17c+09JcS`DTQE}ktB-4p+Efg2v%x1AWT&ATK4h&-l7pu`$%);QKv`$5y5|lzOcL) zN+y+p^6Bv8w9u;%(@*rH69I#@#rZ%fy|Fu)^j8fc#?_mZN$6sOTyA11@yOy#9#?pcyvY8AW)UK*y$+-&w*Ow0r`wf7j2bTA9-5~7r;(xG_k zx9pH!m_f{8!F}%9Xz{@iN+WsY1B`R03$|BS*~>*vpr82f&C_^uY~)DHocH+nJnAvK zGZ{4MgHXJ;Ao(7)0=GN?MY z_a`y{{P%19Zr#s1T~|pp^2*B28o^UhS%zc22n~YmsJyiX9+0tuPY`j(f~00`dj2P_ zyn0WwDJ{=u?X9nOs~Sy~N!oYH|M4Ptu2(;~onlRh$>yeJeqrHYsDdT$^QZC?UG+tA zVe~JuL|dw{>@|Y)56CY!w+t|v>h3v{fV1m%VbCRWKJke0Z^#;iPfyP}{Row79@dcL z`XN#UQurNwxudOWSnAWu&ihZRhjd$OlvYY!Q(U0=#uu;7$^~1??ai6g7N# zetxs~g)Oq!WHdGG9vSD@Jeo1^csyE- zF^TeIfxc{hxuYc3Ba-z7T4%l~(eykc@B0KGKjXY`(8e&LjNh0&TDsKksD-UR^4%P! z(lefk#)5SlW}k>!5}t*eN<(1by9k{#FXx5iyw9BeWSsu_@aZ@-h2qHdhiS6}3&FRvOJ&G0qcfMQqc7P`L&r|{6s;Dv72bR$Cid^R%3wffO*A6VQax z^k$yp-lDaN=?;-p<>h-OI5)=wQ3Qr{+}2%Ig6$07gkR2f9dsX`Q7(Q!M8p|;E7z8t zLv}E!nTFBLfIAIR2|h|zciw4QT3Q+h{pUO;$(mJ_b-xrum&-mUCVN9Zeh%1zTv}vr z5A4~HZ`D*V9PD4UVI~Z}vY-c1^`#y%8|87CIAvU}a){6lJ?LX9sc_A$x)ft99MuCG zMc@W0(Z0vwZuN}WAW~u~2S*~_X$PRfPQ-4Ov9O|NJ(;Advqv2{8Z}t?Z8;Rb@+J*| zLzht6pOmq@4!Q4G+X0d4nl_yS?-TJ1SZ`nf*{k8ItU1YKRLCXK672rfmg@A_HzO{a0=%{fbuPe1B#rD)>lXLBd^WUEDe5*SxU@1a<8NnHns)jdSiQ3gg)VX;Sk zh-4Wtrw(aR_EJ-To&Rj)+SwC_Mm;hGC{I^ndtyI1^By0ePAIcBK1d)BLd5ZZ(LTXW zFlYCFU!|9x{&y~b{s8W&-1q#Qo82u;@+hikYusVfwA5kOY&|{~7FO(DRlywE9HK!9 z7H$^lZwh)vg7Z+~?``v;01aqH(jnoW5>h0n;7z1J`FAJ#U#28s6O|O%Igrn3NpnT< zvLwt>b{cV`V1x^!*?wO1k<+F}u&I#~N9IDNVmON-DvJ(okM|}-pd$@VI*T$BDqKSG zl?n~V-_UY6xYNmX*hd7V`B;2W=s9xUnI?^c_6r9)48Iq$st}6|;YO#y@{bJs$Zg5b z_Wp^rQ-COni0QDcG!my4@aeN-we|tuz*#{7?B%Z^Y^d*|{aG0XtmqVMNuYpE1?%6e z+DBG003JLYz!%bY3rb^zazA{Sa>!2U`pyO4nqYWMii+IDSIv)6;#nHV6N}RfDqnG5 zXSA`C+Iv(bL}gQr05CIawjCcDhD&0BRL`~83vs+IU6K6c^tLG6ixk2J`7gk?q1f(ghO_QBE${Q^w_d$2x||Z%OtN6^*LB20R_6(hrCOWS z&yG$`Of}zS&UXEUle}*#HbGvSzbWtiuC-pasPwjz^8;VJ)u2?)tf)HSl9}`-n{8I9 z>FGPhg|K%IVPfj`r+x>Lc%N&n`Mq&I-o^U%2(D`mpA-KQm!8{|Vpk)rSQrIA(Q?|n zYHa-9_2QRU;aQxuu-$KUQep%6Oj-Wzav9SQSaL{6SL`8*H0Td!$)mTs2N{~GmNq6b zh4vH;uUchY$hA3c&d4(Bt^;LZ*1hgqY{qouMOwQn(>{Igq! zH_SjWLY|HR8$f`>>WAVu*nm=q2HsD!ex^V zD&2F;bH|(V-J7$r5!;nFD5@z(L*v?WiA70YA>Ge%XpkDCC;F5Z=9{Mk}Y z7WC0#`COPZ3Yh255DsWx+zQU`eR5uAatEZ)K1FMOt`vSCoE;y#*nik1!~L7S1r|}PTe$+>YDvr`l_aec=WOB90Q_t z<0Cf7+R*PTUW+@bv|kOOYY|==zq0mDzJRNPoS3RLinXzfNNx^ZLXz7!f8UjI7@_LYXrXhIrcvh@Dy8{Lt=JS5p&`m9-_!;@@P3o24sjhl&n$7ww@XP zaa)L*jw>bjg0X`sk+P{6HXe<<^RrO(%<%7U!?%Dmk3;&nCW5dZ1{&4lKkw&P9uE0X znhjeS#>=~332vO&LVaNLjSBI}}ge9g7^D+zv^oJ$q@JUu@jo}YK`H6IV$zs2`O zm_0m<%Ffy`oo*q>G418}9E%e^GhIW;-y>OR~`k>$S zJagJE@7TG=o#eRStCQ~Q%lX$WjG*sGrAq{*NNcB4xc%#Hn^gg*e`*pQyE@!gZVJAI z+JSZD-RsAUw)aJfhau|}OUEwo!4P99Ox^h|giK$j`g~cd<*GCbRP7AWJyfeUdm=tK zT+HrX>xdjRNKYj@@M1dv+R&~>xUyPh4JXjqg7HVX(7;ZQFs%xV!{OPu$=L?|_gM;% zltQ0VO8To2qmwVkYs1;>4cX&&mreW-*y(-? z(GU#pj9BL|2iuzJbjcJ>FcyD4fp*EavqIn5iEwxlwiJ8i% z8b+@^ICLu|$%A}o9b-+Ot4_TGc-Cm}{4QObp>3AzZI_LRRXmA((MhaY)gCygqtJtT ze2~wSBT%zY`Eg}Ml4n-mvn^MFk(3#uEGy^0g}va&HFB2oCaOls(1~Wme zb-$}+ZUBgjxQ2)HkJX51YI*Bb`j(avj;+#eZuc*>wQ55Sgx~`>-3GCcWof5&f_0WH z(=4mR`a_j{Q;{;n4kGX}ML1vA6)b}_;GI6M3?8?*$uMPKO1SMY-=a4-2@pvw)*EPW zer*WIILRxa6E<_>JOtO1)L>qYF2e>*A%Hh;SHeua=Zr7@$s{+L_4Wd2xVdvhYtOCt z(c9wC=85wo(u0DP-}#f!w}ys9e1+u7&QK17{HhJdI*L|roH8i^D`=pI#6-?B{sd)S zg0cRf=OW{%)7fF3AmAXezy8+hFh;L>fRD%XSz|eYtW>3x6CzV2rpSu3&ekDj5dhd4 zoGoPKM?|`di{KpqqU94o(re91&3-V_MknIFYMp=KL9SDdsjfzDd%~W^uyb^^3~7_B zbHC*Yc~<1YUUR2Hc=8H6B6pPHay~%S(a{kpQ0o$pVuAYFv%HL3p{DoBXHb+cXL{&) zrnwmCwgIB}l~zlf5sZiXo~To_8+{?wY5X`!gFC7Cc|O<+AtLFDRByd! z7~dBCdz#nhi9H7RW5l@nh`5u8EDqN1sl;#e;o;#i@+XAgd^RSS>$HM%q2{&%cmeC} zZVjdr>0qW)P*A|R8?t~aT&KSKa0%ply_x&fpjI`qT%F>6=^SH5yeaXyyc=KCRt@}e zMuvs~;8Y!Ll}||^5AWyI&HZD&w>J1o%MYLKUS2$6087^gkW!MRBD+3(_iIk{TFp_; zJU)Z>UqSfPotHxd-oLMN)IN@yyn=Tid;~k}Ko>r55laq)p~9iaGwbUa`oImpv3$pmWuZ(LHS~1{fiK zwK%JSX<2(Vk43>(l|?+9B?WydGDj6hx2qGi&pR!|Ji&jU{?&$?6wRr=_d2*xhlOdc z(#-c>6D9@z_c!nzoCVf@y8gM_m?p&g_n-W^#(h>Y|5wprGO}4ylD6qd+=5QpKSkK{ zpUu&Hh(!R2f1X`a?Lb*&!VLNNZc+182klWp6v7DEY zoYGIV!!o8(2H>EH+AE$5VW?tRp%;0b(fkdF| z{P_G^>uJp^Nuvl^FECbcax#l|O78`xM{q{>Khs!1xk+I0m(^2&w1|jiby2>Wh=6+A zQe4KiCV^L&H}2v2x4-aifx}UP^=}GTum%6C!Z;Y`HpSDj|EV4PpU=Vx%wOSu@c(!F ze?dd|(|5 zq9~#L8>L~5DgTcv>;DL(BLy5%ZT$ktr_vEuUD3 zC$4TPRl+y@cP5JGwcn8#oEGpyWuqG2#x?p#Nq0((O8))!d(@5X@DtOl%UOGoB;7eB z0vQU6|ejQP`N@Q-;W zUq4T9cHK#KUD3r(CmhS?b;LTeis{KwRiq%zq)c7byq!EtW73IWuKjzRYkvV^>Apu` z7aFVKbEMLH9yfwNsaEWw8&eaw#m(_LVHBdzQ%Mo|7pmi~X&T!h49rJ98F`) zkd0z+PbhWtI_hw9AZ z3!hQ_^QJOF;a{WJMTbA#4J?}fH_!WX@9!?VHrXJZj?#R^KQH?D?yO%KYKak1*jwEcAg{We0<|`uX{td6iEEt`no_7C z-j_;p_ES#_w13Q=zgygW-t-yI39onN+w0pSLfBxhiwY@79U=P1ty?8n#{Pl$-{$xM zJgZ=qTs|gH63K0~p)o_Bhu@A*25d6MT)M%LRkQMdV_P!5M5pV{cu5 z6tbUxmftOy{N<*}%6AvMX=>;Q?}hN$mRY_0v)G83y}(r!lZfqBR{VbRAJOuswFUuk zdC<{9+U9WR)y&;=5V?@Iz5~s5+np*^Ji>-Q757t^rH^R&@2OzLN)=G7^* zx&QnE?y>ts{r_2N@L~Cfg?VFYSTX6CN14+8Bl+Sg47Wq(>1e?KcJIt`y2aYR~wa0RW*;EVn&EdN=>DIrr@v1 z!JYKQ!72-;)6@O5AEj^>>M)zSJoOD`^vKCQ_}WI2p6_G)HMisui25EQP0bl%Sd0}V zJsmY1i7a*$Vwn-sDi+hy8Cco0@;A(BTmIo!t)l8yHRg$xbUqtMzo zMNRiD*@dfHSF`>weG9t4BDPs$i~IYq!|#LZlCugI!dzN# zT=vC1Oq)D?1kW)nN~!I|sw}Qu8Jk{JtCs%PcXH?2gA?9XnUOiMCS6Wj9&(*ss=WW8 ziR3ehvamNoszgLn#^UvSC!I#BBbUc6Gt=)Yh7BGLsfC|Q%5EipVb4@xBY*DNqs1!O z-#zQlG|0zElCb2~eL!8cWR!1~e+YVDlk2&7byy(Bs$pLy2SF_-rczn!xPyZDaHRvwhg>R|fMN{pG84)(%$FX_i zAF2IUbByHb_J8I@TF|;RMJ{uWux1r%Wge4e7+^{9`XEe!UPMj=U_VZzbvfGRo!ehq zW}Y&17^YVrsu6gG>$;j|Wo1k(S(?p3eBj(%>CJ0cu=14qql3+UhK8lb^p1@`uVdHH zHxdtjb&{m7$~Li>GBW}YqPSq;+KG5{rsmT@X=$+V5@=gacznl%#d)rjFR zAB(#;dWHC#XUYB)v(`t`d))2!HZbDsG}9g8zQ7PeIp3aMrYCZURf&9(VCqbnuo4tL zW4oWb@$tR5CYnErrt44^X3sA4`8gd0M_rS}Br zQ12HkljaH%GSlg&*^3uer!NoAz&ktr!2W{(AZ~gSYYBjon@uPGm$w&0w_9snYw7q@ zy9QUc+E(zCPs-9mZV2|@oG&gG(Q2wDGM&W6va7BgD2k`eKHf>^c(QuM%9I4TgJ#zC z+1i(q8^HipmwqHa*hAVOLbwS(=^fdm2a|VT0IyYV3$ZYr+V%9&dsbU3kMfFGm~;GX z7^ZX3gYt)*iW;fE%nOn*XENVM7-_o3RnC-Me{KKh74#_?SEUoQ|Sb9}g z^{val@FTJeeVkjED#$qB%`VE~`uhEHhaz9#+4XD}P;<7oB@#T1%eQ2+Ua2mH`)g4? zBj$P%s^yxK2jsTnL}( z*bVw4WOpHF7SdWz93k1O`px-=!Y!kc4&kNHRdkueBs|{J&0(?X_H2L4^llu9P!8@- zqL}D0amb&vuOD3z3rc9>B0psHspA2&vzUdQ%rXGiXB-1?5a^k+vaqBPoYa5qzR)lZ z<#2~}bdpxBgrqIIkWeZ6mFo$+H)GS}RY%Wk?x={6pW|!i3`OG|KjTJKWQPMk`XRFC z8pXRhk@QcmI?fb)un_PK4Vh^)b+1WPC#%Fp?#5U-?#7UHBMC2Cp*6KN^SKHYGqu<- z!scX%HTc_Q?ICH)ozdN%4opf0>Cb0cV>|94XU+jigWrwKsC-)4SpbR*DR>#FdCTlz zXWWnIR&{N|m|k`e7td#@x><_!$$I9T!q1%Id8UVFM}<^Gfzu_*^p2kS5^VAMwKbuM zb?S4*-rf;ujtTOi4gVn?*f@S?%Rcf8=~!bahZ4&zO~5BAr`v(B4d<%o$>7Q%C1#RP zfxfI-msqboUPU%7KZWe{A!=;O19y3ntfd-tFVuvzYMX}I^BKXqx07IWkE;% zH7bUR6gbZ3wEmdwS(WXCv`Gb9UAs7jPq& zHUSGWCb{U6sF6Vf_Hum$JyuSPvn*UJs~j0C0SL*+p4S`K#)|4F>;SzSz8SeQo@60&Dcxyo5cRT!tS2C0gLWPk zpl=~-5(x3kZfAq(HB(D;?O3(wmFU%&cz2B>dkx_N-{t%;&ktNUKHFJ=!3I9cfQPL~ z2n?OFGkV^Zq)dmNTj>{Zh*`ct1jxlWR6>lTh8krq)}|xtYcT``OrwW$u@_UiZ<{fp zA!Q_%3;6VpdA#^@(4R{RnZsE+o&5UE!$eedJunx0*(0BrP(n)q)Ch@Bcvc@THdiB@f+6KRh}cn7^ci&;>3s?QRA$~eyV zdxgg)^oqtQfgpZ(5aVg?8r?`ABO^et@D2#y!GBUj>v&X=jm_HL zohMYuu}U`;`(w^GF0@82X>U2S#2c3r8wi`mlJ-7ae2_AIC}3B2Ty zWYX6t|E7=hysy}yaFRP6C2#J|H?OkA88TV>6B7hepn+{_BoY8^WRx&ZNjq;P)0}CE z%5pJ+1t&ZHM3`~A!o9J(Wt`<{7$JTpI3~Y|n)9-pRfz5&8=JESsyW?%NTUGIP>zBbrTPVg8lI>yDTw6z>Q*KxW3{%8jItP6zv8R^sV;}No}G}qemv<_dJ z2L?t`=PnG)fn3yO!KoHE9>G3|KzlNlPgaLR`Q-4h;S>_t(i+E{Pu>lL_`OW?%fm>Je0;?V+1PjS*)pysJdUxz*glG zhii9Nf*SJrNW_aFD;kXDoVAAyVHUpp-?;!JcG--IaERGn|6S*{a57e0Ix>90u?&-?Lw8*Kff&cWQ9MZCYZocTxN90N2D>|4@}z1c?zir6#S zO+9j*LaO~)n+7N*OtY4TAdrbl!AfQUF&AGWb*~R33y%@8W-f4P&&_@Ds!u)KQ zygcnPjA)T%?0Cl)gul$P$yS(H2N@= zxg&1gbF;W6zg=YEthnvoB;D3q+2AezSh<|*xLbr1Xt($wJ&?!l5`PLKmPX6TGTGGR z2{zp-2s6KwZDXiQeLm`3pW6vURgWYI5g`OY`sks>T{AjWePks-yPGI#q0-t7e?g=H zm{psWXJPtxJ2%(!<`MPO|-ocm)oh9aC!Gfo2`4HdVtgT)%+!}r7I%YivcWcyW|-v9TzI$yM}(tAXa?|S z<7+RBg*l60(?9C)-a;&q4v=8~CfAXnLWhl(O1)5~^kR6&zSn~qBoOR~VMOR0{Ew!322NVPpe{1AtX&NyM|O6#MtWpmAC_;ErmXp?#Q0YTBS>aFp7nXSx=Bt&&mX` zD$Qm;1rHLrk&GXq`1VDybu?DbHxLpaPNQ~|NyzIp=%3Zp%yFN^GGIs?B+zB!GR0<) zHT@p&9SH&g(CaX+vQP$gB48npKMEf>k*tbP;(^Y6y8@^01%JGoKoRCqgoDO*cJj22 zaBQmHk`?(?Y)TZP29)L`=S#~m?ZDpS1$t1XD+nP{(Zb298u86}C8rvBm{5*s6=7z> zwH6dafr3u5q*&IYScwOg6%MvWtP}Td*y9YdkSad^DDU{{-VxUHana>MSeWO?ezOmj zKMwjH$!)go%2zg3)|F&=(z;BjOxxtGP9Z;AT%6V)#4}Hz&Cc93h#Ls-loPCt@Xp6-D!T6XJ_?6n8R_isFir#-v0;La-`B9aDww+=zzU6hQ44uH zbIUd9Rp8*l3LI;QL0Pw}1J}c?IKlmGkg((W2PABj zYA(X1E_-D@g-Au`;EFvrFATHPQ+e*t7*A?Qx*bGVF~F@FJ%$J&&FO%cW-Zwn^b)S}l(iEQE=Pm!*={U5@6r5Y&#MrI_N5uU+}@W+iW6EU zv36nfHz1YENKs^yVz`(;2;3IO>RIW_$qKo|wC0Y-W;4yuPtD|xC+o#*FA=n$pUbd zB~G%VD_iEsJzuc;8UVGothk}ZZ3qqaM8SFD?jH1gKYiPRF@Q??^!Ijz+x|#&D|H~| zP`Rj?n?NbeO6*tQePxG*rkiG$~ znywDWpFDs@lnoD%w^2`sj4YABxLdhXCGPlKTG$qMvZFz=Fx8~JVaJz#26@^fb(Uq} z&$iS!X57y1Q6u#xW0BnyDp~p3C@e97RZ~~9OwIBF#CsQc7}85Z*7Ca(M0SeV*@lu` zkWAK!so928;SHG9!8u(I=)H&B5ME9M@&B*`artFqL&J!XM~@w$QLZ8VI(d3F?zc`8 zU+Qs7qIbeQH_niVEtLAjx>g)KHQ8@FRm9GVOmn5``@u!Tq5JUl3+#^GAnw06SJ@E~#tTV5WlQM_ogq{lHICa<;3KYzZQA3{^D(hw>B z9HYi$Koo14pCS1(g#mEv4Z_iKcLDjP`}Tw+MLxb@+_P%YUcXe>v9jp2oVXGgnX7`h zJP$~zqKfeFPfj#kJ9G{0#s@>*H+ez|vUA1svdA-Fal7Zvw+W`@K%V!l!bfhFI$kY1 z42e&nMssm3&YFL=VDDc)(HkLW1jC{4!o$7e&lJ zJOBrF(AoQHG;xh>@H-KPdvXP_6UbQlh5^}En#`EM(FFg0!jEhEL%7oL* zvL?(exK;!Kc!bs3;OhCQyCKPV zl*P+v9`eyd@Vi9Nrz|||JLhyw(eg&eSh?PCvn2a%d?x=SL zRtVY=@AvcOZ?gWtPVaj&t;d9JAOBX%=oXNrS(wB#<7{JJMV)69i5%FG#Vn@6vb)i4lRTTD2MCfjRWa_8jFLOT)WnU zUSZDFyrj{JWI?W8wQQWRX7A}>+pc1PCU{czS=H=bsD}iogA>UVJ7YMY0l3;rz4{jH z_**S0P!WGKYBJ6NQU717uRj>^4v+FpKt6ViPjB%*TP9DPqVfbd$L?&pDF|0XjZ)9w z?ro2`TAGKnyr$&uPO+A%{!oZ(Xc`f+>-E0IVd^P~?>Rj7l2`8)YSYJtNoKPIJLF-p z*0VMxl(SO*dflzo*nsKrOja=*H+%Ic+_0+X@Huf*Wr)&@%XtS;Ym;vn#jiDECLAw6 zJI{ddcPNujrrGDsiC$pAOK0m2Dkb7U8v;n9=$upNUrtqKsD8Z94h;{0i1e&9Jv}R_eX*7vF zJrSQEy&o}9=9cD0Vs(A95{#6L72(pm}ose=Rd z2Y$F;KYLHuF&0&PqPrg*4McTd?6h&v#sPFXw;mt;BK;e;Bqq=Re@ll5y_X%VW^o-& zmH2b4UwBbSWs673>09^{7H+HIT*%@j@GqA?v&~-14YED$$-AG^CSHyO-_T;$n&O%G zUs2`Oy0Zr%I|qO>_c9?%^m+qE_cfp;foCq5n5=ymrmi8qmkX>#CavK=_t2)mVc+e| ziU&7LXT^G8Us z(J@X}HxH}FS{rbHr)%zPPjm9v&F<`1ak;n&3XhYnCUt~%l&r1c5r?DbeUnfU?7w{~ zaVR*DL0`Yr$?H=#s&(jAeC>7`~%uBvSoi?)c6hO{63vJJPFJ5G(&4$=vd{e ztui3q1PYncpFL~qYjrNJA$W~V#3r1!G7_axq!|Zvip#R{2*~)!Ax}A727XrpDph@? zYn`;c{hJ(Qj;qW=TOJ!SNQ;=i)*X3?_+WkmH|;I8um11+gHEWME$0vRBc{V|Pio7KP4)cFR2#4gs0=0Hg5ovo#@S3{&axiu-PFDBg zA)GCtn0cuXbjo05vne_9_J zo<)n_s{?X~Any+q+(|+eIgXBY91 zi{F)b{N6(IDMD7IusDVDrl&kGiDgSo(-wT0|0|=3IkRAPAtU8DmglYTme6Jy;eQ%;z)ZS%p%JBQ#r!V zyCM(ce0J{XCgE^+BnPbpH}|tpp1Z-RK;Hf;1LJ+__9M{#aKYUaEe~Xj)TU3fbodiS zvw?7yNKb11!;&*~1VL6Kfmhq4`k-a^7SZuuJ;0pv#osxg|5T}bfGe`#G=jM=Jw;2Bj@?z}m)?C?NAE7SdT z?IkHK;Rp?uMB2GX`Z*zi>W-hV3ZwzleU5!SNU?Z~aFN_}jgwF5Y`vJ$L<3^PpZ|!b zwOV-?u}8`|Tf$(Sv>8*gsy{8s!bh4E*LAP}Pqsh^OhulSG(SGLHhQ%uaaB@EqOMYW zr$3|>=F7Ovav-a9D%Hx55a3xE4D#ogj1?M2eWHNFrt%!D|6sFL3Pw#}1(eL@x$DVx z{HUKI7>R$`S+}P)N}e_JyAq(a)Z!MDW0FGtK`RZG;qcSA3+ z3j1mNGv#DQmfr0RwH!geDgHb;$Ctp{g(=Op2w#n2{FIa8}~<@Ob7W>m-9n)kCd1gmLr4Pio>-o z;O^Cvb<#;@X-4kV3WSCJ=4Rh&(Y?iM9$c@hD8&6|?Cgjl9$T}^md-CVld}>}m*gRd zg_FMFeDVzeuh}oJUV1_O{|`wBM}eII+eN{lAuCdFKk0w#`tR$8*~uiUzE(Nv-6!te zf$)ySC9A(C95T9KV7=2FT_Kkf?3T~)oYss;(%&zc6@1r^nu_scG zA8VQIf-eUoQ3@cxZQX|Xc--)6<9)K#hCvW)oGPqG%9Lsc~naSx!U+Zy9kX}A=V)mE4-^KICRdwSwtgZgV^fD=0zOmP zj7B*-w`Ho6Zib%mI&)hF^Zat|?N~&R# z6+-r8Wa(*Z>wQs0>xZlXmXgU=ApzM`ay)tK@P0I{H6I{Dv<#WzGnLQdM(=b!N=jmV z${##fg6o?wY^QU&imaQ*#{nk|sS?4R8NG8~CR9(+qEe~WvPp9F;u!lP=}tN3-r;|W z|7aFbP{2=MC>&UmQ_UQOL<~|rT>*Vl*IFjibME~aWXV19x#IhI?#%4`SW6yozFuzchil+9YQ{HQO4Oz9bMqlm&l~s*3M_H7Ogb4OarEj&GqLqujgo+ z&Y^?PpSv?c9^+x7U_@7jSrc4d-d$T@?cmxv%-aUO8@746`OYP+?F=U%5X5n)x~551 zCciNiw{XX28l;)QPDm(5O1GR9QHEN>) zX^^(_B@G$}u5>{sf7~cXm2H8tcV|K)Gh-MaPsd2*L$dY9dbI^D4TBE}>uu!f_6%{x zJod@g?VeZ7?VRvR$mA&qgUs^hYt7`$@?~4l%?jlJA)j;W>SvS*>0^-?7A!8VUPZ~6 zh0b%G9UU|b-nV35~`p$Q_Gr7llAR5X4m6Ez{+lsIf~21`1Q zos!Yiz1YaisunugX(KW&;^2#G706SW7mBY=&<;uopHER|2>=_&zD3k!qRkWlO;&Kb zYaS#^o6tYN9JjAJauTfR$*7ozD5oLVF%Ngd>1`a+E+sd!jq0H&#(lU&CK2qKTysXf z&c`ctxUd8s51UX_Vy z|3J!#jnPe}_w^Wy1Et!)^Al`cGO|t9!}m?DCQiZO=Kx8!T`4Tm=UZej&D>xxn*xzd z4$aB71#m{6B)EPQ*3oTbb^?m)UjF(0{L~Ky(Bs^kE0H3f6XJH5A-G zG|WVZ>R=&(RGUbkXulCDGjw$Z@tyHs2W=E_jNP~!|@a16X?-k&D69O zq9mFo%UJzbIqu@42<49=I>>I~@1s>4z{^<9-XeRD&P>tz@*(i`(Awt+B>Ejl9#0Lr z>+IELS)e+R2ttv0Q7$uy(ohAvyHiNB7KXNZ&Q4qT#1vn^xlrtt-A}fjVarTqsd|bF zm?wQPS*n=q*4ofKX$J!;2^BFRFD7}pQNSxP`o__O#W%#zJSc!;=Ip)z(mWq9bdGy! zbvhy`1$>kbzd7^=3m_HL-s*v8*8b~4+Z-~Ls#uPJ&=*M^WD_xcb@XaLktm1B=r@ov z0!_!rj7EMj`iCaU!r*)QBnHd8>AX1(^>uW9gbeD$GLx#}z(m)mG#+a^C&SD(h&1?u z5hQOoOzq#_-W$us$vuaDPPDkIvG#QS0Rvb0LqhfAXt=~bW+6QkKQ3*%fiK30>Gm7T zbG(Nyc)44}__g@!mz=MTey5ur1udpAGO*%1wKJR|hPi%HOa*qh-ePE=a{X8?^zs4V zYWVz$KYbKde_T`c+i7-RbBh2+78)FQz$Snb=PPUpCKiu1`UZrQNI=vuT)sTTO)a^Y>cPbwhHMZb*AMY;_*J~eyaSx49J?nd}vhuK#p$+ERg zsRc93A9dv8$-eZQh!sL9n4XMfqe4hyQ`0t%Bzs2la5M&;*%uZ+$vzQzw}q}<(`~B( zG}h=Q2lgTcstMdJMCSmB(k6&$D&hoTi^xcPwxGhsd0LJ2q3X&G(fJ&rOq;3%%;_Gn z^k&X(D6Obhx#ZnFk52+FH+OPM`quEEe8reCeIWYz*thr1r;_G!{nASMR+N&1J%#$Y14(zjc zw!DC97d^^D+vj6FluvCz#)5uHBQ+f@3Kf>;6vDfrnY)HCU?N>_ee0Pt;I+@P3&ga>zwo+O{D&w4LV#7IR%BY^Lp(5o35ZTmWo*BMCnz6O@YO)&R2EQ^NTVA6<(g@ zr2%tDS+>{1ZwPZFH@+%Th4dB4_f{<;AEqFJlHpwf95y7(EUgPVD>D*V73OHn4$O1m zf48&uH!ULLsTDN;fVkb+@;rD59T<^t1G}TA*Jg*hDy)Bz4TKiul;)%~2zj-6mCu98dtLbfRo*ktHG-1py0StITPfBKi}7wLOOt+tt~d^qN?g36T^i= z5Q&MqE;;p${1u9Lm6y)nAB6vLlR_jWr&pB>cH3 z*vi{-h4%3_mHB{d<)P~2=!wax&qkK9Zd%zyqGbh9pgDg3s)*=(_0cLp_i!}f%s%lF zCKm&#-+~9R7~gOUG}5znl?6Wm)^$5P?a^8v_?y}I`-W2~i`F)zdMRgUP*PNbB4hiK z;crCoG%4zx>KYrBw)wcHBq9KGyEU%IC`Tvd00Ss$=R$t)c8u`oKxnKhQ@BM7n4;6r zOQ5-LZbPFx#Gz%|OF_~+%3shN=au1v41*V33kCU#YL$oa%udO0&&_M7>*fn*nz&KR zzl}~_)GoZn5F|=4%#>@6FfY&V$Vm*5{z4bryZx?ZDYcl3`kOuV2Lr#!G@cZqtgdJ( zzNg*FGf^#pC#%}gvfaVNjFXl>E7;C1?4=>V6nqH9g*cxY%89?G-1IANNq9@D>Xdi3 z^%HG`l{qAhC)?i&yEu(fZ#KB*HkHY(p?Q_Np`$ZErat9B<==F>;X6ogYq%BpcV)%vsO;rN#mR)}TO?pbDl5 zpSEbQg0Za{tp>f@(NbelfR6ND<+}bafAB-^Pd3a@Jlzf0+5L2#ydZ!cuY!?v)CgtV zsI_WCNl*G)VCj4pOn(_Y~&br zmWZ^X4cb^fW=C;FoZ6cD&f^3Xu^zv)jT+LS(U%qvfqjcGR({Vwj-*1mEtTb&prS_4su0AL-R6q~qtMgZeR@-ljs(`9Cs9`=s^Wc9@8 zef$f8ZJfquD_qb)`trLG;rcjWhI)AS-KZ!-cc@Qvb}cN=1GlvmCYW?U?kh+V4}e+EY1%Vf8~HxyON$x z`?abUn$ps6Gu_dek{HC9uZ#~QKV#&`ZER{NjSgt9Zz7YHboj1r5|E>XwUVj>V-%7f z&UuA$mXL``kc6miDClrN#q0AyvVbctRc@?TFoY(u@uy1WZLNu7@rwBhe5CJ_vn`yvCek^11Sk4|=HYH1f* zJ3rEgOlh97c{`*|_Hp)26u0R7uj6zFH~p_{p+)chkLUw4E?d-^wpSU+u9y^Dt|+U? zsc=O$J>pyF=3ShZ8-0Y;S60bV5wt1=JA-8)$hB6fD_qrk#6CpwQtcMo81ivg#sqt* z-OLZ{lKI+(=H5}N1_3qaB*I*KdoyX!t^Ph&L?~%nQ&=#3pJU^QF}3#$I}hYcDB3(Y zV-1{jf31@7dD@kvBAqsl1;dcFVRY&UPsF`Yyj{!0GvBvIKf>sI&Itqx&I>bPUwjMl zw)LA)Mmvs_rpTmB(>3w*OdSeD4z=}*UKbb_T~TVVW@z~EzSek7Ev4n`U30xPKOqnS zIX($TJv|HH=$_IB)!+O1wI*}ll;h_`6Opbr-AdS8N%B;XwDC2m+kgDjN2xaReJ3lo zO0@T+&BQ?XmYY4CajdXdKRbT&AR)YpP0Wo_w$IfSJ4JJN16~-eYFCh_5_PkZT0L{b zZcoQ7O8sch4k_hzzD#`y2!}mlwW;4i$$KT>D=#AGb#)_>>B)nLI8e-4moaxeIll8d-+TsB_3?85yJ{mnt?Zy z;_u7}4A}g2{EJ_nyI!UxYa<}4LwRC zH)72++geinX`t`RcT6-{?zB~lLa+xOQJ-fZ(X9 zubCB>-Nlo@xv~0(nzpK5cGc*IAJ(k>uv(^WreVAIjf<6Qdl2INe0)$LGIts1azDM> zHAt%0$jUD02FJ7%teNo^8@!TnXdw2@l!lk*6yuwyX<^|>@$IrU4*FSDAESylan)qfFQs|W>g`9jfbmx zRv1|NbmI2;Kj4wS@(*LIOp%p}6&&2IZxF@@vSSB!6Uif#-2kZ*H?|3a#%f)o+jAA@ za4_*TO^=AlgK-u_9jEIzMPRqAyOuGDaT4G!vD){UU+1|UOgWI-z#0`TrYojOE*>Z% z4jvix2P|nrv#a<8-5eDJ&Q`*EHVx~msBn=!YDM2r3RYG}%B)BxAZ_K4;vlESc_$9E zqk!cBj;vL!w1+m4HulVDhmE^ge5F&z_HK?wBiRzGHN+36?cWU4bqdG%8}Hg$Z|u}O z+-9ai3N$yHntcKm-M8i_)0P|VuQGw^DBl`IL1Tv}^kskY4`by2)(-$WfL-aKY8)9_ z+bcPe#Ba9N5H^ulHBBpqTsr60BI6zhiZ2Sc*AsvZp?>q!a?%^&`)n_fqvWjB!~qWw z_%uLL=2zeCF++G4S_sSvKb%_vT->4gTMJ5;gxfdx7Qu&3CX2B`5HtDP;a9 zAO($>xc$UlvZ93N1v@)FkTmO>XqD0X6A2Se zb3g^0zC=jotYYa$2t+qi}IrLs=wsne?FO-K^9g$0bwoJOF}uQHzYLfkch`QU3RTzR z9)suO=F(Z90Wz=T%ttTwZqzLN+WSavG~pKEzGz9B?v=YT)=em6r<)_}NPLHFAU@OR zw(|n5@lZFUr)GI}YQuuwN+G(~hImj#GUbn44Ni}!CaH7u7k1EiubT!sEB*i=hjyU{ z3y{{N9BAh&s?5E=68ibv4$dBLme_Gvk0#(hBj9hSM`8My#vJ&M>{?QSi9me6SlhsM zfzCcCqjS+?;db-ug;zx4;=(+@?x1DyaRO(q%DC@#XekB)uW z)F>@gX`EXJyNhFuk_F_k_pQwmhJu?i-v1^8F-?E5g+eZWT6@}tLt+}`Yh!+LEFnW-Ob{s|&Nf5gzr z1DCAg2-d;lB6vSr;k4L8%pr+j7bH>aA7g7BHs2+;f)Eb`32tT;M}J*)Lcy#6}wNUKoP%18LY zt#3b&>g=|HD`Svf6QS1f;hXgF$>i)l`J6|S;4LK#zkmKMU;}}oEpS3zcQWZ2M?hb& z!Y>qGM%E3p8;QqTU)W!M2gpA1blz0beHHaIvURCvQ2T&2K>r`c8|aJO;dAt_K-QPz zhb_SpFa#7ZAivrK50(gr_+OHGN?@WU#4jGF5?2{Ljl!U>MqTiBAdG7A1;n+&HSEZa z;7QT{qES)&&IY%BbLs|N??yGTT7F$v-P?#^KqZjlvgFw7m_R8x+`~6=RlnZDN3(&{ zXJYbWEPmoCIUxIOi$-wQz}+g@@%(9-wEp;7-;%`rXh7gu2z;haG^-=z4lNaOeMn+Q z68+%$Proc;`~?IUyyk#25)@q7BSlMZ_u%OFg>D2abw&hQQhfU*je0jNW_dMDaJ=Ug zP5^)iwD=&(SnEc#;Rln{ZIID@BZ!RSv5tz|59tm<*Niyr-m|lD&?+x`Ha$Mx=09P! z>u3iWc?xzC{Ng)#EDCbPA=Et5fe?CRMgvN^vm6?;0B6YRxR^mQC;xPz^M}9Enrq4< zU~m(qnB>?5?c+qt0&*px#70E4$V~cOi5i(%#;(S%)65LUpW7YlXSN8#`vR&4mmWE{ z9c0Bd?-y!I)ACNMP$R$?rhCo&g1;^iFOP+~^lb!&ih>CoLc>@wwi@)Y1_s*`b&^yB%H zb#X+=P*c^BgT&4Ei8i`Um?`?+7wpZ2)*laDMp2QdwF@OMCj|Z;a0_Im*HUZ@Dq)djm)b^o8m$jX56){Pv9@V9?a*B$W zsjsw#YTN3>*FKwB19Q0#jN~F@@=`iLnqewEo}LD&L1K1r53SPoN`n<_eD;25!jIoW z69oGqXI^Mp6}DFwCPDYtb_bUZM2oAkVk_1B4&g}PHSom(g#;EkMz}AN%HUp;{W-<< zxKCtKrhuG-{N|Q*$Q4LspueE)#fRGE(%QjIXZnE&*OV25&NXX=uwKIt=RSVuXt1zl+Z)kB& zV{^@1)E*e~gINz4edL_)Hw|?<1us^7?N3TdNlgJ{H)dQf{my8>3jmC+%8sn|8OX)2 z!4|qc_i~Ex^8D(P6}qhJlv2zvIoU%``b>k+f_mNuR-9N=4=-JnS7E_38Y-}8@_rU% z2sFLFA>NVFL&CuI$L+Qr?b*9`$UHx*+L_12YqpO`3zxVSdZF&P-+H%{X7R4gVsuQg zL^JB*wcj_Pp)HV78J8{0%r9mAbyg3F&`#S(Sp$UFfOgHw`=aNoTRVx9bWGijK2T;H z*VPl{&*2HTtEbt)ZOe>Ct?Iio8J|tSC^YOYx^G<$7`HhQZ8zmLuO2R2`ceNU`d6}(YqB6O1!lcb!q z4^tQHiswnrNY}T|j_hcFgEHTo-*ZO^-k97YQMZxF^r~3?@u^bOKzU|7!uU46P-B6b z$D&^55^v zayx83eyz}Jm$A`fk>sbiU0Z$N*3Yi1?ky+Wj^8ea&N}R@=&VA5z3|geeobb!iA8b7 zv(t#;Eb_XEiTbqZLdB}H`vGl1m!P}UAI_#{SxbQaBx^n9q4 zt>C`iVSRBSaAC*SUH5o z4xV*5sVUKj8BR%)m_XsvKEE{-Os}!Iforx%4`>pOQdUX?>+H zXPcI<#s=5v{G*ETpP+ll5!8d{OlO1~FC#Zz$on+f@z4OUcPrRSB27NP&sKe>p$K>< zCTm<9w$mVErlBFLQvHo|C2Y_+(td;SaHJMG$yPUg`|0Hs!vGd3h}SR?QlskZ7`!6H zN?%!*$Zfa`-ni+N;dh{ z`VG4ga-e<6{CfLfaqa`JlOxL{S=T0Al9+ItX9lT{YoNVZsD%|J#v)ulo+aPF;|`q) z2NE^|7h|OEPC0!*?R&&U&IFm1p|trFUGJbEX9t1s9?fu$FZ|BO+k@Tj=7dvr4tB}m z4#Xl(9X!+-%0Ld=b5tqH_%?PC;iMoeS2!(tCC2wdOdvM4+O8O{_BZ{WQ7mk{Wstw( zHqG^Z1@^H~iKYh>=!rfpp|lyW${5G08)9;6D@crfjUfu484=w@I21GwcqNz4qt&*yrikmj&Xs2Wvmh0B z#tw8AP&eZIbqEfkds6i23a3SbW((V*7VIV7PV)%oDbZnGk!mwx+#uWNwnaVZJ;&?a zP0^4A;O#J3VJwcJQt908B$Ctyf204al(*^+=Kk)eEat4 zYYJkXg0H97evn~?V@1*y0WG`AZsHy{-`h76?Y7SK|8as~#AJx&tfHDC--6Ej?=aRn z9IaQF&HZZ5-Z0z^% zIV*|-P{)-(6|CM6n!}1r-01YJozV7~&w@l75)|<*Ta0pJ7ek|XSSq!3j!PEm>hv)q zmOm6c@LXu~ICQ_e3bt^e!p_dAYdvXM;Rgl7yFk^0vxxrko->emLuGko$gc;!nae8( zBH|s_L=PG55GDW`#zV~egN3&S0HC-^LgSli1YNg`$((5X)Zkt1lxa!$;z&tWP`IqV z-5)G~@@QU@{Vt70Wz<~aH%yFj^Z!yz%bO8wyEI%D$s-H0ZmT=y4F=j`GEH!3wfBxWz;58ymsBK_NUCiZ1Nsqne#y3GXe23Xt4p8dinHpa zOV>0}crT#yo=5wkC?z$OH4)MVnmK4j4H8z)gm1_bGiXV8E4| zG`RmwjJm(hL-ZMuQ+#@`%S{qtx+MA=t<9BV2Qp>FmkuLWt1tX%v9mHQ!K;?J^+$Y{ z$f5QqOhX9j!A`SJ$z-2Z#z~^SkIh^+Y&4@I^&Tv{?p-p}IbJ$!_v1l|oe*ka*qF!d#h7p zkH`GIlGS4XlPNF%n#AoGCI>@9e5Ie3gcM(k=*qrSvrIZIY{Fv*F8w|b@Wp*2?itXo z<8ApmwdLj_zdIoho)+SCkpwKyNfD~hftyV0!gRhIp3u zi39hA9^dj`2Pc!s%rt%{_m$*a6o2uE1y_{WJ^6TXgT_Rw`@E9qg1-_ZgMvHC#O(>kSVVZ!$M|3W&7ax(}bIRV+%nwu1=#e62eJ9V{1kqBA3NtIZaVL{t zLfJQI-~-`y3=z!oh8vgxwoFCFYBy`GF}Ddf{0Ln1NXZkg6R|9oKNX-52>m-K#C^gM zm**kIcvFPy`61aptJ&dZ(CFz1w0XV+DLOuZaLU2_afpQsstl>%{?WXDA1zt_THF5X z^OsZg-*^1~^vnLg7a_s~o`I*Ji0;PARrp7yV)R`5li|H}35tN;_6B&O#d7=z-QPZv zN~!U|n?T7~y~rtU&b;(8{z-Pc}D(+r}_7E-c__C#%Tu!Gu%*@lwV*IN`D55_>Zz9KtjtLo<`L7EX zDqljA|6kv<-2BEt-1@o+%&XK@5Q#uWOBwic>)sP9y+ zJ^T7Vo_O#(g!`91M~Mp#Z&Z+Y-<7hQ9j?0uM$OSU{Y|p`zx5bIEu1)^e;<@6ay#9* zL;CXk(qsG~@>CMRlN5NNovgbpiCf_Sw2$&R%X-Aguo^pH{r8^|L%m)q2Oc&ZBkK>R z-lRr?2XRh#BL3%|tiBG|4DX)@ULN41b56g`F~ zf~f0zE*N0|sqDs!Hs&18U&NjtFrE4DKTC!-&%|f$0gH-{8t-Lx| zGX1a8#hqE9uHT#%D1^kRULAQ>;)rAv<`Y$RamTj|ntxTlCIGq^Lv(7Wzc|WS-3g~A zdB3#FKpxz(v>-B3s_>6Z0d1|tZm5U_zFyyUd3n++Y%LG9%=dSI@(sm{$}-~Yx;)P@ zAYVKGf9sGHzR1Spw%=^@n7jTYK=j+fG}n+`Rdjex8JP*V`y=t5;2F~SZf2s{qG)bg<{E(NuW$9bZQ?2N_3pK-aYp-u$%<~P+7Sed!eBB zA>;H+&^LE}O{w0W0wwLcGJ(p?5ubMdYnE_f?LPin`3|6I7V~6?px{h)2UY7Ye!?T zw{j0HI`vbr_{R`|_K$sDKnI|-B00~0nI5e7mq}P{fm~LK63po`%XSm z{B=zbLjH1u)-iTw85Sgt(hr%@_?KuDB?Us@+TCtw0>v% z{j^O)RsJCT?MgHE=><>{=jGv*fSF6bSUP?4X z4^i$Z{6uB*sbZP4Ro){I?WM8KZW*)m5vy8SzGdG7vs+ zmrvJco2XG+sM7OJL*c41_7=)-W~KXBZr+k%^t{Bn?&b4c`vIB@a6uo{K*LG*XUGbg zGzitTHmB2wbjS$*wD~@QimA!&#C8=hsPa>Lkey8!)SeOr;8ku zKN6`*O3D%#oz!8P@%~&?kHw@Abr$S%&P=)@V{{(kN}_~v>M4?)Qyrz_B}63Dlmw1K zo?1?K{rGX8EkHKC@ywofcdbj8X zwteMUJqvS8Jm#!zQcSm3HOUVRcp$3iMdrP)~E7_#m zxYM>Cpc*d1LF&Tv^skB*JY98DuKMBI*^%_8TSQzN&^f8kA%o}sM_ew&*(3>~yGz8R z;7SMU6_1vxF>Y!GzvoP?t&Znf2%8NNd zn{yAJb2iAXZ$||;{{dNjU6)?FFo?DhhyHeb$0qZLJX^CpITar~{`~mx*lDv$F*o(u z2SE9WdSoH8R2wfGl{Vpk{FO0yypH*={=Vcsr zF3}fKGVVa#qx!-gAp9ePd4_?-Wx;5b6Y`kEk*EX4u(rKMQ)NAQTAWCXNz9_us7o!! zyKs3_$c)iAM`pX9$kG?l78MxdDcRws2L-e*jamLw;k;}J{$&4r+hE&wb21h!F(p5t zzxi}qE+2_Wv#5jB%g#t|n= zKD}%Z+KiLxSLz&dGkz(l!J3FqF)>NkCsR(CC1E9ghDu6QN?+f9ot=P@PW*!Xwr7jI zr2tdW?00O0!TA;Lv}(fl5_@R{4o-v-I4Iv=AZL0CsIq#&@_n{$a z0>ZS#yJ6`}&qqGE0)IRaN9gr*@LFSejvss$f3NSs_FNi|!$_*=R0iB<_*S>a{iKCi z`yk3OFU!)wE`a~SBcmi5(FU%7q5-|mz`)7UV5&AL9FzETwbA3_z7c1=qf%!{#7}HO z2P4?Fwih~qL&?Ds-LZkwm5(Mtgc{Lo6RSfunG0jnSG2DDlppOnvPz73b@T?dS%?d1 zx3*dc8*B%HFxgjVes-H5SVW(12kRM(%Sx(id=+n?MN8U0h^-LkmGW@lxPmqKFt3V{ zY`yKO!a?gk7n2qrcK0(N$6PilfP!+L;QV_~!6BJ6U5)?G!K93UlcSo{f?U`ds$4oG zJ=`|!SS9SYZ_UZ8WQ(XKCVt>7r8=6AOUciMlrH^JN^a?2P$Fd^F{4VP19wP8e3$=} zNVSsUW(gY9v1GuNhy^SkFFJoXlPJF!@Li*CWR-Bv_OQS{UA8B%4*Q}uwpt2P<4VlIdU?oBG znKC-65wBfcDy7_dHaWZ z?IXmGh~ACF0DIq@Ce#?!2XXA@otZ7MouvYIGMh0(T4pA*r@gHd34V`0X1_KcKW&>HTxt0S#N4<2x zz-9cN0m%v-S$7-%?dS%(?2a_zeBseK>c)?n>6;x2QJExEhLGA4UaVHR`(QvJK<*pIqOkW#t~qvB+lxAS(ogm?Ku?QC&dTi|Izm#>_h$J*e>mDyEhf zKO2G3Tc*dC!UQjrk8#_+MN0e@UIlflz^W??s^@7$5u0Zl7~_Z;5x?A>(NRy|3p2~`uX;{n+LICpetU}x}Mv^SY?c1Y$PDctneG<*8*m>La_@FEP2+;WC z^s=G~m<$%{)6dlJvwLI=93LgVa4!xu$nLRVzxivP`QNXuh{TsO_jcFzHKYy}Q32@b zO=3C8XQFYcS*Am zIMM8c5u3w<+fiwio9$^Ac6jfpxIjac@NQ?~Ki+%6y5^IWA5+RnsP2i8o9=y`LX>fR z(Gh6!5hE$#AFuX;cXjUiJd-Xy*ROq40BO(u+5HZccxC*>D?hj`)k;-0p>6N^XF$Q> z@B8M3^CMkDr#tm_Ym}QP3pg+1!IW$2)%Zr(; zu_>D(xC=1)?Ay-jY=q=xz@pGM$+1OiRqynMWR9%SG>Wg0t_RHOH#iAn9Eqi;e&m%B zHSr27+JMbb>!P=q)JOIbsPm|!ztlWnODd!n7-&(aIUwVWCny?uW(O2HlVlJ4kXWuk z_Af8zjFylpvNJUm`)!K0T)8?dX|1IgGya{i`)J`6i(q5Y04nD+N1+GbnZSXd9ey>;iC+LKhL zc=Z9kMfad$*Vm9+R@$_lQHJ6&dU;73;MSz%HQQHpF?(+kH)+#L@$Vc~Opgapw!Z~d zUyCYzHW~4~Tqztht;*HGC!UHN&P7p6=lGg$EO>Ug)WeV9D|zSBs=g`X_1smOmf=J@0{Gn`+TfN&Z5{DZX^KJ$poUj9y#;DB$HZ%~{rs&A7@geCmor`%LJ5)=U#j89DXlf^Kbj+XTB=oQQS z)dV-^{~_zEgWBqYuG>2=0d!u}xGQ>_p;rqeOme>G?wYx%3T%WiM5i5O z8ut#@@+2z79d#Qq8Gq6I@yt6hnAIz+eiLz`fv+M(rik;lprD8%xi3?C8dvR%j>mj$ zvWqjLc>8<0z(93#jFP(Y=cRdckXN#bYwg2YuyLw%1FX^)=VhLD1x(F3!*jNg9)B=j zoAK)cchVi$WvzokQF*#NBK9wTxCbt+d7|Jh#$0A#4)^Pr0L34 zzai5wgF=klWuiWFlH|^uLqi?)W2|%6A{hqZGuz7PzN|iMPU%bciPI+|%r%k2aJTu? zV?VQNZNEN25PjOe-pn>1e{+Ko405YE>psHalp~yLu|=3IAMCPKB--6KJ@&^r5Yh@| zV}P_onw-U#9r6AThWh7F9`o+-#pHtAIrXi6kktJ)a{=^E(aE2T9J`-s*!>8&z(sX> z^J~*QHUlD4w;a0IKx6fDbX-e&>?y==xN#Hie0>RTq(TUl7L_$oi8Z6+ogY)!gL+n# zW$XdpzedE>1mH&)JKi+;i-fJ*^E{M+s?7iqis)>J`s)sYF}ui=9viXUJ<7m`43;R)Rqu^p$ZrwxNQIP*qLlX!eYjZ!+C{ih`hZ<%G{saz6_Wdh7}uTzxD}x` zqAKefc^X8!2kS|4fi>@=u_xao*Sv)y`KOY~oG~_R-*ExQoQyx`(2q#lcm-t~>~Cr; ze5fyF>ez2RSplpOkAB9tE{X6woi@};Y2GPh0F0#tyxE!Xyc>0y;w7dku|V7pM=-f_ zaZ)*?M zR&zoUGIIy^;L263re5l~sp3XE6^z-0`*GJO3nfhPMo6ikP!Jo_k1qPKKl1+@FJBzm z*Z*>8P$NghDj&S>2N%l9^WCdk1u=iAc8T$10Xjg@`PX_ z4<@uBdQ5_+Y0gPofLCC3P^V!m++=f0No8jgRrtq5LNIb+M0(2bIALIq)%@Ls#%U!Z^zQf`;gto%m zcI74uQ0%JKzi3v6jgF)Qej{jE}(KXyipYAjyt%DO*!b!RA47V!I|J>g%uXVq`Yp4ftUn-8OEpi zG5|i<7rT6dl%k~5Fi$Zu&XDJf_Q22@XM?g!v0-2i5T_s#p_xw&cJpQMNpK3i6kv zNcBm;m^jZstZMSS^7hc2s72fthkpjEm?QlKWTa!{$>2qGivY^=|10Ht*G@-OgY)97 zmR4y%+yudSrn!jhuo^?K{{%ybWC0;LNlt4?%#@I?;H@f8ZImwjJl(p{-5N1}PLR5q zvQtCKkv7hz`2^BbWJlhaV|0U@R$U%22oIZMadlnd0YfO0F2O zQZn+Uwrav-Tz{38=R}u7eBk)O197kAFQeidJd1!sG}O|b>oVC^7D{+1ti&`XG%hYK zT+wFNO4Y6i?zW87%jR8$f5Nj}z#F_G9v2^wtw>;XmEipr?56x2>h-I9$NS&fFr~!k zsnX06wr~XIHD`rW7Zv1tg}UneZUsZ|DV(j6cM+&v4Sml)Ntl+BQ&5nR*oKw9;QK0~ zr+=gbO}dr^WxW*M@(zPm461M_g8?2@&ovcsYNJ2rrqM?h- zfr3WD-pVS{C8eQH2v)9(%UCtt_7{!jyl}FW{#4hq`q|ajP)Z?XD0nvB#V?p&swx0x z@;Q+*tGF;?A!Wl63*}11y#}K1g25puq@aVqL~iJ?f*#0$;^ZUli(UZ%bslBDz-8l%;Z@l)%= zG649JiQpC*F^@EZ-zQ&7G$At6w9YCgJ2>l~E^lp*o9})-S&y$#ogaSTn^k86W5P*A zq|LDAQ2u2g55i&N|9BmbZ;FusxG;q@`TJW>lp}V z4%L`KC4&Sy-iW~;8#bdR8jg52C{uFWJBdyjRae7zVy`qi4HDy6v?PouIW&nGiEJ?k z6BCqE|8^HmrEy+@RJN|hmpQ&(d!*JpfQqYBDq0K^q&{Gbu(4x_Cr0H0wAlzvB9U;a z0P#@pAau~?Y)W@~X)58s+*FOcM{;kDk5_&l@^O}ygcVv!h{w@ZBW5MTaWYR}PlB%Q z9+J-%TUJ)5n#?b2LN@SNUi zpHo=~Y8$SIHut>-K?D{`=+3Uy_A1>~h4-^)sij|)T@ip|z-M!n2*=sQ)y1K~HMUZE z?!NQ(>&=jv7!qnU&4Urc;<-U|X^TWMOc$+WY3}1TisxIQcaB~n(>VJV5AQ>4~+-Egc z+`!i_<%t1yiFlNpfuOF{k6g6DYXLTb5@{Uf>G_AC_lI37CMNWRGzeArqEpksdM*Uz zx>4AY$T^;di`zyxmWHXrvWX3#3Mvxmfzh1&X@$kM*Lw^18X4pTwdOw=7KiV$Nu8!r z%e}|Sf9dR25-#fM)K3O6H^OB)TAu2krduJ!Zka0^OH82O@X1)!M3 zlZ8?v68I8gpmLuF%hF5W3^1d)Rm;=k8w;1c;XluM2R7=qVl!Y*VS|kPh*!-(Rsn)^ zZAp-un=Hr(jpdY3kpd++%ZxaaSt00iwnzuuj1BQ8O*SCRtBT`k(LH%Lj+VwCmn2W= zezz>xspCH|*jhcSru4^PDviluCp9=#HN0zFT3Zr1l;mDBZnxK5vq>y$2=7|w3Ls6- z4#IFfogVcS)aH?p7sunV|D6l$3S6|&AQZm%qt|=w0v^BkhO*%DIqRcHOoAqJ`W|_1 zrTfpl4Vt|LB%%p2xLSfj;?zmgLMV`t9tj6bEFMLx$8i#mVODh(agukZS!)IEn2^2; zm9RWMSoLt`Q4oH_UdOtbZcU+=uKVfv4<`Me%kTYCepXs91SizvP7zsU^({ZPS!ie~ z-oA&u+?{s4X4r?{lKLw=lKFAt6Boe>OWN_u^u?tn`-7y+M(~5~=9_szH z(v#2YwDRtr1PP@G`)XRSPOmy-=5@2h>PvyCq-WdQ(!yd@YM)*ja(kemAHD21@xc!q zWWyOBx7B0KktrvR(x*0TMq-J{@zRc+fP9=%B3lM?N=>Q(LL?wFs;Rq0ydwaU?12j{;n7|;O8C#YMW^>TPR5a&3X*c{K6hl#OhiHYLMAbXRGnL=Fu$ zN&rXB^j|LJS)6>ATXwh7(Z1RZCJ;WOT__#`aR=mGWkVfrbe;>$JM<}?Jh~1&JJ-Z{ zOqa*exCmKphMAxE6P=!yf4PX(SX_vkUD-e%0V|d6hfbMtz3+0SHVsMhM}|hyFq?%Y z|Al(oxE2pmV-CQ44AI2eUP;;Bfj|=nyM_v+i_u(uYI1(W5Y|z|fuk{1rKyrS8a&m{ z^tP^vhUx05*&`3_l1+=WL06A7Oew#hH#z(Z^z?zhGd_p2?iz=)kzx4#3P(V(KWvMN zWlUU89)H3kb@$Y<_=;jfvK^+-HGn@~r>eYDt;5EP_dnM6a`5xE?;4O^OZB*+^LcPy zUPq=gpIFpO#Y~I8&)8HDc{Y8znEhhEm~W|sl%l_OOktU0Jt`#@2T4ycnq5~oduo3` zrMT}!tC0hYwhMB0jDCLxP~5DF&gbB-3Dx@CL_GJ_r;`a?Lt!{9C-vW-%YAkoKHw$< z#yqFqx7Wq1bSb^+L|{2TRd^E6hr#-SY)mqDKYoAcDL?sx6S1#I=eZgedeg5j(&3zg zT_rr`{Qfcd`un3aW_s99eCBtZ%_)fnx$U9bdLCiVHzRiG<%b3UaKnaa+zOB`h2J7A zxo__>Zm%XDdXSaPn}(|$@HbIjzAi?0e8JAl=O;B?Q}WEPYLfX{bxPt})+7bs=;cJy zPG8l8n4dJ(44*s_zn14-!a8RZpr4_?fJy*Tk~ShQCIzx9Qm6OWmW!X_3KW3WeO0Q$4G_dJ@KNRgVx8fF>k^e7(Oi=i%T~NYJ?^5SHAu zflZv<`a2>qi%7K^Cu1R4H=JX9sS{`HU~7AfY}I0$a1ZPYB`3+N{GCx*7(I5}Ys&Uf zHmSUooH(bbF>0&wZ6mFzPIFykRj17-87G#TPb>@uQz53m3W#=JW+<}EQwx!hq?-nf zU+oZAT0|;>#MuQLyx|_BNabEZqf=?5wg=`efap?d`YLp^Kr6lU2{})3Hd;&kI|ZJz z;i1}^NB}+4NC9xM(S(nT3`H(!+}P1XvrWwV7b{HH#Qd#PeXpgh{kq5X#cl0ZGd`~q z))&Ubw#S2mKwysXG?~EQ*h_LS+GMw-`dOVdg(=tcE&a%4yp`I|;4PFs)rq11n|N&; z&Q94qyc6*zcr3^`qjUf6ziBTGZ@4MCn&Eor>09nP z<0R6Z6^$5oTd@?rpIzP-jtCXX&4Pp9E3zC|LuNqSJ zpYH5Ep0A%n-?wk8m~f@9@htNV+de;-wt46ZyJ>E(yO(a+AKx-7*pz2d)rZqej3SD9 zB(c9hp{;GjgsIM{%ij+NNuOF5@qk0p9kx7F`^4uRn*98uCzDxTA*MV6e^nLJcROqx z73*38F6o**FTRqz7imNG_2UZ`W}H|-r;8?AAGkwd4=-u(RO2R3d2N(w%@57b(l=`n z)z!a&6z>r{>hvZN8`z3-Ba;h^E}@*fm1)Qm427HQ&m5Mvon)NAdH-q6a)XR`{E5GX z4TlmElV%@HTSjxf&(7O$T(;G2%wqr1)!;!}OH=Ksf^okWS}5T1;~BhuQAYo9qbF3v#+f1HP0J zw0;+D6r{-_=AlfxZ;UY_w{N^0Qup8{z;2?WL(^Ht+M3aRRXbo74P&rLhX3H1Pq=(~ z)={^kU$(`?ENHFioyUSnl~`IS4BCxVS$f}|EWn9nAnS_s?A(%; zA@uNO)pqmk0d|*An&8s`rIn=V5qymjmOsuv-&eL6RY-S7NT?<4s>hBmPR%PcI`IXg zW^C{6C-#9W{-x-Q8|;7ic#m%$_rY#iAEvSh`NYf6LrnT* z$O*mKCh)3&(rlfc`N#Ohwl~@%`k`Gs9LR1wEdtwbE-?hpkH^M&1?9S0LdTvn#?E49 zk>)P{w8B~4NLU_+D5^*58NK z%ks`+1>ZZW>yu9W1xe%-gydEakBuKgYI=}$B#s_N6&jr#xty8gNJZENw%ckSbt)3o zTN5aRU-TFC9Z`iZl6=NmZP+RhDyo~NB{$~Yb{W#6Y&edI2z}m#0`Xr~ES@wdYwBe? z(%{k-`+GD2ULr)IQGRA=>h)5Qu{+s%!j@mUpIfXhKAL(23Q@w#UL@XpV>f_vpB!VO zu{RfD5n2~=ff<4G_K0@aKq%kenf~v>9!T|zLHH1JD?lV|LBRErBSs2peC6Ped}>Bi ziJX^=h#B%n9&Gx8$JY_hmzh{$;6g2RP=_pri%T%QPMo}{-lwCIR%}^zKz!WI@Q3E> z7Lf68L~$fJIpBdYr@u{|QiBhkKwar-2o(FxRi5vS$=Rpk+woRssj=BfkBxV>1;ngb z>?G(}5b&Jiqt=qU9Iby3-x7$MZokfE4X4_W+%GSUj@&y$2$Rw4W#rK3je;Yd`%+by zbyA+e8~78*uECCRHON2BRp{YvV%u}cum@-z6ktdN4ug*DH(uw@0A<}j5}ABbFW-7J z#9K(m;Y{Zrjah&?YG4#rzH>fj1C_nHwt@8@TA!V2MI{|?CcJZMs*UJf`e+Fo(rgBz zZI|fW1LY~W5^e=m1U_3^6EFqd=I)~c0~WB^j>}oo6%nrh0tMHTIcI<%Ib(^O0Vg4=^cn3JZQ@o2)r3v3 z-wAG14zX$DZ7IEcU(JPSRaj&y_FsaU6J-T7k;fTATJZ#*gSJaT69kEPtQ;V)<1Jc1wTVon!F@xeBz=gyQyRZ;tPrK{0Vc^il}$t9m)aDlF}J3YV4{&xbp z>L8?_!Ch~=P$mZx9T%dwe%+EuWtXJ=t0mic+_S(^BgMjzY`GoJb zPDR(>MO})T`8vUMcJNzQ{U*4K23q~w!SVgqaPwIcbbA`%&4gu zQ}Ww~LRm2ON$mPMq3j?i`6FOg$(tN_}|7C>n2&`==*+6u40ZHi59 zW_EzK9MP|>{1ru)(f4xnt0y-a)qZ%RnQ^3J;zB#PIQ}*wd_;DF@%V#i)%~)LI+uR@ zEq>g;OFHn9Y0J{vNwcg8(Ir|K27cjgRc3RBPJ$@%hf<$ut0R~M>f#cK48Gek%C*K1 z)BZV>&8o@{ic&+|ek1ovTKyz<+v&NrJ}!Q?(_dxr0wn&&f|8Lglxs*7lquFN^2=(oyqrNBuI&tD0E29(oxv@8?Fj;)sT&#`{>kp@p3jcKBa5o4ikFc z3rSV@NFtYe|5#cIG_y4owv?a33pJfKc0|YIVf;HAtED_L2)ZtLzgn2gP*S?)%k$MT z$)~?6XePd6%e91I9AU#F@yZUN$B4F|=9e}X3*s$9GA(Pfa^qE#?Hrte)Naqv01yt_ z&2MQ5`duR1?`jD=7m$*%HCA>u0Mme&DXeFI_m(vFE7TeP%0oM%egk263)amYmMPUs zl+>ILwv_^-o8U67cU^~`%wDo$gJSm-I?dP&$3{)}6Kmf-dgdQV4J>Z~kd z2K89thW+2CW~fI&kNIad6bhwhVfjAAV^y|~8zWdBnjz>E^yo;z17tDW-xC}}4cBO{ zOLn0~=Q-MRrg)@~X?t>i7^$-Xy{fcKzZ)#@{M?ixDeO*SIrg$t`Mcd3h2O2dPrilW zVwV8L#?e??cgEo(!!gJ8>0$egpk%$@3pdn)`ZeOH;KeIOa)o)qfGwG>@y6Cwe#=KOyux0jJsv~jq{Y}aO&U^jYLF4Sdd?Sg1+45SsIJa z&zLgV%?+IPm9e&o?ky%gej~snh9NNtl4EImSh?RC@h31-ge2`CWNTfpu|A4JZsZ{Q z*Rju2m(7^YWFVDrH%<&ieq}*MJRQ;^MjuY-T3(0fx%CAq6GHvQH`# zN-umMZNgp^Fb!_t>P*rM!Ij+93%N@c)$8ceobHZ;@K-Q-__xgBu=6hwGHCZEob=^F zq0lm{Z)(_|2+_+cb!DwS#IQ{Nv0%;Y=SO*A9t{zqqay9Dd0BSj@FSTTij49!2D|0# z{h%>a#6^#|FDxQPQ4^n{jg&wXpA4f_<<#vpiH&0^43;07NV@G+aGwO2pB9NUrg$gb zmsd0sR|eIME7KC?D2b}$bgN;=aT{>;$KykmnO~7i5r~W+>e&xcA3wnVGF63u3%?>Z{;>^?8IF}>1KuO`n+|_&WKyE zW66Tq-IFvmrB;G1Rwq$>=txsc)OU626dW-bdA`q0L>p-qrHGqrLa}dOwn34;zsfON zP94iOR!%`?(iMJPIr?~4udQG~gFSC_{5nC(Cz`S(N&)Wves*JCsguLzsdw9RrB6Yr z@*#$eF*Dk2T<_$Se)I20)oPjL({DH1_JYIi-*C@=r=V3zzv2(GNQFS&;W(zj#(C3z zf3X=H?)Equ;p*g20(@c1Ut`-LH!&$r{xK4L18VvB?mH_DO5ntawl3U6v%^GL@7y)K zi;sn}#P31S@ zy)L42w1!P$7~3Jgue6;k-%z zZq~LSqT4SpaWvC2J1e1EaFsOd3e}&5h5G$zqIjSyInwB30uNT$bOV_@Eoh}PlPSxx zO3+#bTsF|ijigf#^$HQV&tztuuj?ra>HvN-Q_I_)C|7x`r7&c;f4=<#`#g!eQuZF+^II#RvCWPA;cxxz ze!=3ybtn(m6bnQ5h4Jt^vk1kk0I*9!l=q}T_P%{G0Gc{hyFWN^J}>V7G`=7y*gHK8 zq^1re754b0PjT>7n#s&tj*rhSo<8>9n1dp@Uelt0eQBwm;}W}mNiFyojw=Sxk-)LG z2WB0Z(^>2)IOr>5mrP^zVxLv~fk)8fbuHQ9esvet}4ezWx5uBi9;n2bx=fsABptItC z@XWRjHom?>B?PfMqmTtUhNLNwi4MX3$f;qLA|a?}?uBe7w_VaOnFoLvTLo1Ls*F_- zEtzouAl~pQ%{Jy>^DSyA@Crdv36DPn>y}6zkJwfTd9iWqy@bz*-*nU#p zI_po=$E*lB^wS3wZ;uB>YK*}124|U@mES21S)YDry2KOwM}p&V{oIqeZ~ye`jr|*G zY@X_WIwlQek9A9CG3d1U{Cl^n2<;oIH}#%7e?cbV5)xn3x=6o2yk*h?=oePR5|6B2 znRW@fU7%~DstnY0x#$y&iE#IX9*hmIm-oa;_na}ERGZ)2w@sDaP16ndMcLAj z({WM&NaGaM$hZVYP6;U1?fo3WMeYWZG!82Ra#bEzqf#ICP~6BgM_Om3rM!ZKo@+Cv z18je76IL?zlrFw`zNhPJT(_S!=Gcq;o3V8=#Nl(mVL68vhOm4q+&)N5bE|(;00&U+ z65BQ_U{^N}j8(BM&J4IeKd{ZW-+%LQvZiDfH@C~onC}uQrEexGk$d|OqsD%QOHK(y z^8z^v^?E-g#o)a_812NUF)Q3nEJYyxkc--GBJVAopem z-r?@WE+t2V5LElpd`F92)e8Jbqj z+HN)pm!Afn4L4PK4(O#j;|@*Zrq2 zoWSOUa{D40Ji@TPQ=7jM%IuA^nt;sVBL%&e&N(hYNXg$F)@`s+`K| z31!=5tK(!Eww6iy)*U9l^jh1PZ-|2ax1YMNWBWDS2%eSC5!#+E?JLbSF}FI*$VnO2 zwKE!{qPTxhEqQM*UOeox%w0fm;HgE9YbFGfgZDS}2}JZ7HwUxApoR99Kle|$@wN%C z(E|@3BufSho^BA}X-w-^rCSlt`Xm|mTkf8>!A|PUYFhiy9hs%kZ{>`1T>!t1e{8r) zMEy6Wy8ZHKu`Svx>5C1Hc6v&<6VERBP|xmU`~Ihod&ojT3XF`3%CaN|ObL9qaFGTp zswGI#1PqvT9$y=Cr%Z6lksdHkGvcDgNzqimYzU)z-A&7fcw~V1)YxGL^$To-=-KK? zS^NCq*&i@N!}``WfcWT0Y~3**AL_O(VQ;;(6T%lbrw#Jrxz4&CN}F zQOzwr-C4192v&e2Ml35#=LT&MrhK#x$92_8F3Sg4X@{cFx`3oDRm*fF624Owq1KXa zhHZKNZ8su1&voYX<-Mp{ z?;d7_ml^}&K%%nA{U!4PY8+}kFjP6%}9imAtAG?9{Xbl^^13)$?awLyh9LmANA zQyx2;CG^GIHxcFGQfU9(Bh|68v5B0RP#QMlaJv`y-exTgmZHHP9vR7^M}F^`OA0B-Wo62y)zP>{W^bjP+`r0bd3{6X;#gABZ;b%)3$<{^b zJT~z1BG#RCY}B#eYuvUao^NgJJVf?bDfbII_h&g#AbHH@LVanLi1I|NZ7KeDUuRX> z{EI+DPr#zx_rB*tm%0L7R>H4|rZ4Q!3Ju`e=k{<2gy@Ax&78EaJF#$fZE9(;?bggj zEKU&o?M3I$ow)|*Q09XlkBW+l1yn*=dGh5?eH8u9NlBi*p{k1zBXslOJwAN6G8}gT z`~NlxN19K&qSp{ov(*DER02LexIJZlX+FKvcRUQe0@pp_r$1a=;x^$;Q2nbs^j|j} z#Is1@Vv*E#6c2LsQ?7aQZ}{||=T#=!2<(3c?H3YXSP%`9kM7OkkdMMYpA+Pcjy3=9 zzV*vn!lT_M;BBuw#WGOJT~54?v*#* zCVh`8+qZy*l(lvo9)urW?bTgRnlAOvK61NG`W3k9>)NvDS3CDfJuhA#M;UxD|M-9I z)WbZMCd}exNog2Sg-5^Cso^itD9L1Eax*F;8afuTh}G<|Jr-el-JLM^r;ZI+x@S|F z{G>SraMkKlja|G5a zCgHKUlUH3F{JRiXZWGh?K52@vfx*kDH#IF6VnNSat6yQ2j=kI1HdJtq5y*&?!az(K~D* zB9!CEUd3_J7Gaf;oMGsZnbA>ciCsnHZp9DNd`*g!&=_XeG=}~ma-UbQ$i&=yy^cuH zm{Q{Io+u@3O?r$*Xe2^OOOP%KlY^CaxaHHTygVHv$B!;2Lz*n{Z9;NF0}B^$vJE9y ztn{CZ$eEAv@5WfCm-{qW{YA>(wJ-QV^rTP#p?A9!q?CkH4zvaF32~y}k{z3QFNnT=x2j}Rz6f?;gxg+ihTHU z?99x!#J>u0L_)eFN=Zi!MEGuoPsAWkHPv--amB$!fsBg|5O|6NvQM=p|2nt+*=N*` zL_MgMo;vN3JkddZ7YYcoL}k|h(E@*kSuJK^^>e9BG(UjtrC{$Z=QB04%!$S|J>LP2v=Voi%%GN=hG_8vB~=`85&{i>Nzkx z3V@lmuIOa^9A@KZ?;k(m#hUr7T$ND@66x&*E|QrizYB?@MH%K+W_Ribog4AAxIQj^ zwfJXN;D4{<4^>n+kiFIJfvH$!X&D(*d_<$H5597Ay!;0nZ8jq6)E4I6Zc^A)G?YwN z!woB*Tz8G+UTC6=Fuf0xDWqR5zM4t!dYVumzo#(gt_VIDex;rRGRaN}Y<8dGD9NH{ zrAVaLsq~NH8ajdDzFNzY=9eeWG@S1Ab{Y$DV?%0!dOr2@&MqcIFI1k;t4?u#7Hb;} z-7rT0NrOMnPT)T?4cSk8(d8O6*k-^awKMP$jxMDqJY@J)uJJ|AmDx%<-i?3v)#w%>OxWd7i7gZ8`YE|GH z@UPf?9RB>6*l$trWu`yj-7TN`2VE|~I^j7T<1Y^w2TXEw{=&-9}D+6a<+S`cUqc1)k+9okD- zO{j-KB1GF7R(<^HcRVUj+jUp29-sy-#?{GXnGz}A*g}hRWGCO~QX+9vW0%)6)_8<^ zPM5jHD5dZdPK*`JwrYi&C;3DN0F#_gynlxZw%=hR-Fa{k zm%fE)dRj^V$<8YxNf8N+`!t3F#3zy?I4ifHB${dF znT>8Dmy0;vu0*WtimD?`P?>``!@c*dopE=1=nQJP+opy}E&=g@se(Q~u2wa%iId6v zu&W?d4;R6G0&Cn6^|7fyT?h#13y7ei)dp09|331=p70(MV>-pR48 zRs5OWz*SoO(PKo%Hxqh0a*&wc6E-Zz&Mqu!;TOHS%79Ib)@lFk zh=^MUrUV4|_;Ay`@}e3%*m#HV1>ea0ixgAG!vXFif^m=$3iiYYW9lx@aL_oq8N5vu z91o5C;|F<->qg>uoFlcMaH|5)o^;zGmp|jH2Jl)i^@etVs$>#gBvUm4fA_Lk}F{E z`Ut+~m%KH9AwicX?eIjzaoqU%Iz)B}Ip|bi2ON#75H~x~-&1%fG z`}NDza4;7-KJpO_!QBI4jtV8G2@sRT|1&Z7ls1k_@0Nrmzauz$bSiT*Rw`)MT0nHj zAt)S=q{w0H>`bByG`c9a&H&RWOeA^ z4$0`M?U?H&EVB(*g_61qd_@O)uMN8fv= zJr9v9nIGro3T*anCwnPw6;5s}%icS$qDbtsgorf{ukrIh;Km+2We6vcWQftgt3exz5y&^uM7FM0wF6IbNXVECcJSXB`#cFH|IJM;AnZiqxT#zy!`+X+&2 zl;^vSf9D0QU?5&H_^{o>E|Qivpd$E?BZ+bW@71lhqdY2&)zP6zU<}xzA}ygLM_bb% zi;&9^Gjog%j+EGrCMm3Eaen4$8|hH7mP!VM#$c{lz`E;3wEzm_EAT&#Z@Ae023OI< z54~tFYG`B|y^)B6Oo&EbDttIx0;wp{CUGc&5QbWQL1$l7ibgZm;i`%Aqn9(|b2U?^2FxM|zZFf&%f~oftVmC`F(1uUCMIN23s!xnh#Fz*y(Tr7 zZ;$%6Sb?+tpm4Jn^Im1PG4XFNefo^zZm=LDS_H5xSIQg>XeRSR+{!P2+B;g=sx6G9 z9zZDK_(P>HCf-6OvquLv0?BQ}#FI}>-F;$uQM$Fhzw(ie*LOH-;w@v7n6EtrPq}rs zUG*wP&1-f^i+U!5*qMXsyj52Ak6sZjT~z%Ix);M*8Z;siDia+iJ;KhyC)JiN6y+7eH*)$84w}{-%0vX!=Uy zHr%X3z)|LvYb{(S26cAC17_s#bo0FfO-u?B8eMKS+=S0^jIGxDlsp|LK4FPVB$^cU zj#vG!d!6;TuY!2p*Is>zKqXt;594zJfmmW$_EkRtvgWzDFE1x12sgEs*3~!#T+>oK zmCR#%?>^pEt`DbY(3q=@4#Qmt(8Fs(E?vd8(daV7e$vIrGA z65Us_dg^t03kvXK$sh4ErA^AtoF~5wEZU+sc z$S`NCkFUFmf|t#okPC4&zFG*0CxdH7^P8@#k2=IImXIP`Jkf9;pVzC}gA=R7eZ zF40#?mfwtzi)DNxmpw}XOZ`X_r&t`D0`9*(dUp5Gb{X*qLF!#MJlu6C5w*0 zE7#y3LR*iNLtnoxqpjr}nuLGcme`_);%`>TSJb5)@*HIft(LS&)Z&yLZyqJtW>#0f z<`U?w{Fz2u@@IMn=CjL$DfPOF<~ zW^@{VQ%b)|S2FW749jbYiC(ZX-S2%{6x;J8v}|U=9yPT}yMngj+|2eM{NTsKeK?q2 z&i}~iZfBIFySY+?Q*w*}2zCjv=@8%EN`ck!Nz7?&O(U2?Qnmghlvn%$V%b~d*ZB(7 zbK6nrk%;S(o2M{IbGnJ5ESn$7 z{p>tEp-2A2EFcim%E3`iUL$6VZmS!Lz^jpH#t#JpM+Rrf!J28tST9d{jsFt80WKk* zYw~Jpyv8?y)1SxTa>){5dACH-2Mb-1+F3fo?EHc<1Cc6HqYf80IFY!rVZ|eI*;zzC)&_CSM^lZ(Psiux1JpG(;4ANFy_1DQiWzr zdX&+28nE?J3v*c@GpXBPWRfVl@15g536D;<5b(AUr< zCT@N(Ob?SmFk=`PQ1Rx?a2anlCE@xD41NFJfi)qgpr>zm<1Gdr!Z0?YEJvg~vc~Lz ziO&HkW93349~KplW6jcbWNuP!BI5;^6ki>OtM5Il^z&n!!&M)pe`|`KlFG5EVP|81V=zNW{HnB*Bc|Vz+clZtL zmwZJ>ph}6^g^wO$3iONfO;`w3s(=qTlwvT`Bwul#*s}Co&yQ^dz1!l#n~<;A5VEz$ zndi2~<+vA!Uoc9((y^%|1L3@C(!;K0gYTlV&2&?QV;7A=WXzf}s=qj|l)gw}#g8z9 zHPcszPXkMb(|e9kCzfX9tbI$NysA1u)NDpkay4bg00a5+l{n*_4*5F!BO0NG&>RHh zO7T5Q=?en{)e-rIGKd4&&aLSvxkzWE=Gfg|iPBrFK|K~X^I9S9BnlGwK~J=pDTNo^ z7Y>B&@hB@&xmGFe`adsQgI25Qh(-WxHiq2mo%^n9wT$$|;%%`2YxO_J64jQ;O#xH8 zImuk~YVhgaFAW4f7K5hi+<;9d#3^M*dPMeMRMVClp`$$q`*W;XmkTPFnpvm44MR7P zIx$PD4>Pl3RQSD~n#=Xxf?tK?aL?B@BpFL!oQNq?!Cff3d3=+aQL3L54D&v-8LwEq z`%u3d6!3cO^p#^~s%B>U_aBYmDCiMaP>tiKBE%4RvYuq2z!98$TU#FMJ>!Oh83x~S z$u)Vf+y5d8v4?=l(mgN3e9O#z{17{XWc(0A#X)(F1jfond&U&6b=)@$qtSw2*;9J{ zgbbN|Q7SA8HmlFEaN}%FGtkA66KbvD5obvFG`ne*XQ;|r9L)T!to7RftIHjs!U13O z-|>M&TcPP2mftD4uM#b@lNfg-f}IdQHAS0hCO66ZnTBo1_|IdI%vIS6L~F7XRT6Cx zZ1?|daA?q(Q^UhWOj-2rGL%#~Y*@!|aXT}Mv@7l?(_7F`LuEixAT?~VFgKSJ+Km5{Cl+VJ z9FZ<J?t*JbLyI=D4atr^~fI(JC0Zlej1$O|e%6F;Az=&($2-~TZo6`j(rEXkww5F1#QcpM|)Z17Z8y*vtM%0$iSYr%{v6VO$5_)kN=IA8% zPIQkmiPbW}y{;K8Iq5u3B)$1uc5wZ?F^n{nsXef!lo=%v#fc&W)jx0jmAUxu2%W3@@9<&=2hB$U`N>U9-)cO*jyL@|Cwh zKPAk#ZZMZ_S%MjHrPcm8G&wYKmInAMX;GG!aMqSlyID?C2?-3hwcZoSSh_4%MAwoj znT5-K-R2;a3C@GC0rD|9Qh}#~&GuQ88jIh@Uuf0WiX`uqL6;o%jdL}2)Y?4m%9zaT z)ip1hoA{h0-isbi*6I(?@j2UwD3J0>j^t~@Dl4NV7QGdL=aYP$P02f)uXD0<^flbE z{;-b^;n|e&3b-wPNwJ0Yk;6t{&IKo4j18YWWlR+Z8D#L#W*Yg&oeXWKt!h&c2}8mx z)!IK~S}FDqvk7wc`Vdpay<+4eQ$+(h*V@iJU&=rt?bfc|I#_V4W)KLe0OA>y*;c~? z1XK!2Ni+y#@zeq;32kl3@9wY9awq#i&qRsm;;IEnU(dB3u7-Mth6T5yDb^I93Clvr z>uh&Bp)4u{DFvB?8(`;D5uc#STheHOmo#m)-EQAOW>Wrtk^`}y`ZOW_TNoAj>qvTc z*(vY%K4zq@elYc8w=y7}aUE0z4kn-?{m3`^orsZ~A8e|XoF8pSNLZpW3OgWntH)5` zDPL|eNUAJc`thxl9R~r~^QJ&@yo(I(+4tM!FJd`p?=^R5=vJ9r%NmcqTn@&#GpXNN zA5e%r&{E5w*aH8>rW%V1RpT-7HSz;Y)p0nR)Z~7MaRKB*gAI#0-EGZ7k4#n$KK79x zZ%dV?rPwX>M754I)L4_GIGIIHA-g#je#iX2fNwWn8I=s)814q17qO2XpmyPWiBuTN zmWz(p$@sYCs&-Bl5@vKh-exD{4)-NUa}*&QI=J7pyGob;o&FuK8P%&tY*vm_PE-j5 z1eMOnkPS_;fe=(GD}Z>RTYp-$BnWH|HluaLqcPAOt)4#+Esp&C7UC(baL5IM6YcEs zB$y|X&B9DPNP3Qjv0Z%@V@X;2N$@)5Ygz}kdG{W5jt9>5EpUbuC4lw(k3O7Dkl^1 zOaEPvGH=D{GE)X7749G<_=G7Bgp6Qyo7N+2nW9krVIN=~Wp_CEXv`3QG?LPRa%G9Lv=Soi=9aQm~>7wSeOKUMSn?BP#nUHVD zqUvkkNc(7s8@JQe>GA2G_yRtm7DySCYsQTM71l_3^+F}`Ckm|f<*EE#5S5AiYl*4F zs2HMM}5n!(d1|g>lPt@h?1z9Xvb${5aO>H%TFv6(U(Th)t7OX z6C8vaD39~Ct-#M)AbzT_O)%%C4+>hK5pzVD1}_4$&7YnGrf=p%;?8SVeMRNxQ{x)4 zfpU3my?qZd(18Ig)M}MnR5z=2L)@+qt^Y^bTSvu_b??GMNJ8)=XwU=??k*v?2X}XO zZy>lsfZ!I~gS*qXL*ovOyKB>Zd*1t-d1vmu|9tDK#cEEk>N>Tnj_v)Nz4t?-OpDEO z%o}X}d&KblFO}i=e)%A5 zZ;TivKRB(*VX}*{49R97=`$`Od4fwL*XAXSx~KAn5$iOerNPK}X8vuK+4eDWa7MTg zQ9r4Z^8TclZ-g8S$5-6mIhnsWs7{DY~ z54BRg^xM2KOQTw}so#43Khc1}K9q=AX+EF|GXo+Pma?LwhjnBl;0hCOl0|Jrkb9f*&9a9i5)CSD##C zLP_qCN1%GAO@>(Y7@0P_k;^B|Mkkabb(z7x_VvGFKueBZ1VODlOfycpR)06KC{DQ%H4I?<ozjr|YYLQ@qwLKdl_`0W!%yB2Ta{woSW(->nZU%NEC>rB$*W1CncZ}r?7)Fc{PUZ^V}H0O~UWxzn$&5!)}*Doiei*yV;2nJL))N1M^tj@Ks%16gp z_z20_cojIozs%%swvy zIOR$a{vuC2{Olw954BBsrc`@My+_O8k17!bM3Ho#FN5hzc06|zZf5#ho1b$4>BH-@_{4#vbEpX9eA*JUn^X0`}@|cshut~ z#HEZ-w8xuRngvazV#5O;4fQNLcBi6Yn-3XNj*7 z5pi4V+uF-ovQJey=4QL+i~CTdTQytC~}<{w!c;-4bP4EN6)z1Dt-Wm~SjE=H!Jn=P$q+th~e6@hxm z3XG#dB+r#&@LkfD+*OSUNkPu}yjr50#z2%{f2}F2s#(-+lN)5NU@*QoxQzzkAR&^+ z6YRu{9q}(c%r^_==56}EiuEgg{C&A)ZV98FF6@k;^yhR`tO9c~qjI_wtA`0DurzRK zuHL0`x%;t#R=j!e`XEm-bWo=;f;_xG>a$LP1u9C3hy8 z{QRSv0glS1<`8l+hM@j#%w(}%?06@=luk!Uxhdkf)gvP|V0 z8}t${6gk~FrrHV<9)d+O7VqBV$)k_F%eNQd3;#igb9bnhesFR~;c4)lJQflrT@qE) z5IBBHRVN*vKppF}b&cPw<9`8?;3+0NUa8JXGuSt3ZRJ|++CSbKWeNGq7r;1*czq;D zwJ<#PLg!DU=dK_Am~O2+zdafQVyK)x_Ue80lhTz7=bxHgdg0c42+UrOT` z=jyq1%bVDTUzvrDv+-mWHggO#17q0?w1SqoYAWg@JJ1t|NQJr;3T^Rmf?Hz7Tqptb zG1t!9lfvUsa@FzG+)fTc1vjhg^{$gFti!3#m@MT4_|joF*1W~2p%=|+-fi>aY4x_U z3`AR_o2yYv*l3jf4fVu9Lr%8~mX8XU37@Gx2>2114-U=A9a%(#oL9W&U7PHGTvNQw z;vXW%gmcF1YSdby`smtnH@Z3)9MgEG^l4=ECs>%Tro9eGrYyfI5gX6qAD;s6Nfn|j zgv!^hS5B`H7@8fkhlVHx0R?HrB01W%Euy(K@c9NFno;WOg{QAjM;Ue|f1(*vV={+} zmsh`wO*Ok7Ws%SLK(^1CGO=vA*yP{eLWA+q{&~Le1Y4~8PoG6y&uXC?YxJ{rNN8in zO+_#G;^=%YRG6xHbY&Wau7v);Ca%V6;Aqm<6WT)?bJ2_m_&#BlwmAFYX>pe(Yk5Q; zax+hJYg>3!^GY%J?N;!<&zU#r8T^Cte{YL?eRF~R0Lao|3>`CrBcUhdd&1S57ZSx~ za&Irx6OfZ~4ctA$<|&KIA`^l^-WEH;>WXrJ!`h4jZ877WV}EPgjHc}96*$AmuBeU$%uzEoa&8KnpP62o zmNZsI-29Ftrg$+xsM%X`ukt! zB4BE4#LU!s9;vkuwO%TYl?W3xqIiEJDuMtIB$fBRNplW9+TUN5RFFW0X6KPr z>o6MQzm_k$@*EgumHW2(@~h)lU#2uQIWHuj;^E=@8S1TjBF>Dpx4P*KRjy!y6|1fydfp%^s0-?M5nN#ctJEH$fa*;EoZiOJ-!< zZ>yJhzv?03qU5BRaoV@~XYCI5y(|w9`;JCYPqeeSZU2g%5+Ab%j51`GW>Wb7Q zk1zuoS^D?=XKuN_eU-mBdm+!yy+ik!I%Ygv_F8PP#R~tG-BL)^LqeETuo2BU!-gI*|cDBoz>n%uSR{>Sa9Np!@q z%}>~9Z{OUXhxP=CAY{0qkDXGyjQ}mp$;;@X%eO`V2@AbNNSEi_-`=T~#iRC-C7EtI zHGiA6zT1f^iiuNiBhD7|Nn2Z6vxb<<#8s0&-EUKO^dWU}z4XOvLR`5i^}es2e@1b4 zeeKHwnC22~jJG|m=!v0*3^|h@^_kNPAm?7o$zg`nUUdhS%ip~phqw$D+fhFY^XKoz-G zY*J8f6+OGEh$7>1Xznjdg0xb-rMttQ!4XPwUL`0gNx`|r#a0~O`b{T5?C7e>e!n?l zl}fM^rC)Wf$ATXC_rBDXA8I)jdiFId!6Sh{jB@^#scqvIPITf;b_C8B zs)QUB+IMeWI&c$Bbm~{gfA;R}%rBe3FL#2HmY zT3d*ay!5MFu#mQlZNDPMr_j;eE0Zs9t)o7O6@$79$+R0V}I;fna ztWfo7P`O`fmAR5AP!&C0PNbSX3U#@4A-j^b;dg_Cwm@hI^m;+}WQhe03ybmQBGPB; za1T~u+?J#MgqPe`^XO4O#&25g`S{=?t*;@_QC1J@aV;zF82V5qr0*FsYbC_Ss0*IG zi#T*nN={~xOE6%*Z|l^#$i4_jCt>q(!t{IM%HDMj78Jbco1flN)F2TUH-}AdHG5ad z!aCQ1i)W<0wQh*54P0@jLj9-8#@kq2SC7j^^zs>-In;QI02wSc^KmwKCiLAb`X`LB z9B(X}PDcS<7A_Rr1nS$1?Pjsdkidnd=(eUxjK;LxqV)y2j)st5wOx{hsq0Mw{a8XC z8Tm}z6-;YiS8J(MT?^%jz;Ov!+j7wkGF*+eM--a~Q4~TCn|k9++B0)J_@kv35fSaI z6YhQv5gP6(L&o6kOk}(E=EUs-UwQe0H}%&JPh+~hsI^3kLc%}>u4&fBSkf$K5VpMI z;Ro^GIKuj2(KM4 zKRlA!k_iI)^v4y6LaQavW4=@UvjEsv#YSD~4Q)h#S*?(@O=ZK`h_Cl7rw$ZiUe=|Q z<+`linU(e2QgT~jp7G%Krq`u(gwoN9%iFLnQmJaASdE2ut z>88Lsp@CQ^q~z>U!td&p;N!-}r(3~s{f;{J6Qaj)^@rh(PtskB_Nya&XPFqtP|_)MLVW2e_}Q&WHalX;mhU30x9J)7v;L(dTyU}O}& znW`Cr8-EM{zRu!z3G;_UO2%Sz{Z3X?#~V0v@YmWXY=p2>Dn33OcS6a}?%{ceD-X5? zvLToqmE}9jXFk-G*BM*SeorjW>ve^ThFI74$QGmhtq%k4ZE^a`*!^eI_j}YGUF+bY z2cFW1Ojn<_JFrh3r`R9F>Ru_BHwx!1+NndCNrQb(k|ug1 zV9mF3lqTxb`ng;J+9SThgSBrW2Ck1MA-mZO9}2mpi6G<29(~V&*wQEuHd*NQYhj5x z2J|PJyPWzr9$$sE(u~VBW-U?KTVr=$<1jlE(}u6%Da^q1GUU*p z&yH<6^HuGjOy~W#7yRcLeG%HL;@wW)y2jyePJcQjm2^J3ojhc!AtKG%9W5Sa;1Ub3 zUm1)v>ljNAs!I9ncHT<7tYLYNoBcc|yo*P;prWpz!NJ1NWjKH_i{r|Gie06G-U-aN z9D5DDuwUyv>3F~RH8p}xx?QV_8Rs~S_{OvHR?}>KuVZi-bEf(UdN*mw#p4DmdMJB` zD8n|1otazxsIr>-ZKfG8G>8hq*3d~A-&nkJdkA_pyOK>Np!MJR?a$H{-XyAxTu8um}C;g1% z<8wzyb*SgZnJ*$f#0F~0S_+ww%d9MQ1bWr06TMrk$|I)qY<)xIp^JRFJ!ZN(A$K+N zI6TmMUlIYAm>qMu{KQn*q;uOf*&^cWVBuRq&j3oSbFNy((yRSA%|D!KYtgbY2b3tM z{?d5h9SNo$k^75gm}!*-`A_K|YTG9Xun${P-8;(yu0VGeN1czxVG9U&jj&-|z>&Lt z9~IuO`~9_pyz4Q~2AJu~B1A2FyTHch?_JU9mR620sDgD!l165&I7jl8XuF(Jm4=4K z>>r8O1Rr^zo0ZTk`#yTJV({wO+N%`o zXxCH{S{MsR#snC?&DJygRO8>(E%DHAtJ?;-VcJ?IeZW4`KK%4eXG>#A3?A!h_(K|( zrZQW{2Wy0Va4$kd7FC9+CcaXqe1?sVGM?&GdTP{)FQ{=5%q#C0UT9vuQ9J2 zx}FoCL1bp~Db}#0iOkidKFE>QG$b~Yawirvm-aCq;U~8b_+iY zHSgO+Z+(;94God>COink<>C8DG1Czu=@tZi#g(b++T;(prg^6GZMYFHP)Gfw$Lyyu z63X#E{*4|j!NIT0%*-a)(HobaWiB2jn9(jD_|pofCMUlypY*fK@hqz6l+qr!z$3yg zyxO^mFdiTf`iMTV;I9a9<#g39SwldkbJ(mFZhRi7e}z!5gXl-d5{BSPZnweP^pmC8 z&h{?}f4V>TYOZbkHMQx$O=uQAKAC16aZsIp#DpJQv%`Ol5gKT~Of!_Y7pC5<(_cex z!%0|LD*Y`h`1cWhi2r|XCDB=`Li?WX6O^<>g|=zc?uCCBhfigL)c!xFmL|70J*JzR z8x`6_{Zgq;fX_m>yyU*i2{lUn+7@c#Av&yr)N)IYbR|8x2OUlHZLp6dhY zV_CB^$@GVmSU7CbFdNIV(!N~zSx%xRNGuBBnJv$$0h|c_Ey^d~Pi=oBxV?7XlfPOB zS4_I%Ewvg*w%FOtTxEYcHYj-5oX_g2KaoGxIP$uc8zb4dilx8GUGGRR+gYj?YK1Tt znV%W+*Jo$weeLd1f;8zaTgG(6|L#wI>)Ai3J(?*nMD86b*>nHa=WKY-&W;bR1`hq@D3fn^EnDbhWli+-K6hxWm&bhT zsVJ=b8BMn%IQR;%i+E-_vI@)8Ucc}p$r_&Od}@UZ39Sr}wjabU-qe4tc@pf`7P^<~ zxY?M$4`ezu&sFiUE#U48U3*jj82TYA0Rg9^YXeEGFuru(qd>?RHD1-W*1vlFr=TV~ zJp(B|zRmCOi7#!!_k?A@CsoSAgec*&Oz_~qGrWa@rZ#)m}&S!#UP zpuT(WabSNHll{qrTGnRU?NM#a=%Te_Wo?3k{QjP!AU> zF-?Z^d-KyBzqYft*7{Fc&}-GB6xd_(eKKregvcQAQkKD#CIy~Ih>R@~DRo3Pht|MQ zM>3&a`UBPwiTfjJ)LH!<>iZrT z^!++23s`9WUMH-&IO6h3 z5fF+{wcFUaq012T&4MJMdu*rupIvQN&%t_WQyX~Jc0$|+!4YZmGzdDVHYD-f7SwxO zpjTLV!u68vs$rHzq+#|oVj_LsC(qYz-M=u!uU(XcJNTKxcXc(?I8se3pd!up3W^%f z?Xk=H06tjTJu?iN<$g6M#>M3IK-~5m&Ge}z2cxm{7wyE9U2T{hqp^{J6`@Awu0pk$ z^l@r7l_G4w=8Z&Z>b*5d_C2x%BeU~X%(I;e(o^`J*o3pX`wJ(wV?UQa8g8af-N7zeRT;bc zS?w9c%7Z*A#q_KWzCV001qVqg!&x}H_m%iGXj2jZd)=R`xE7E_-%r9`>U+?1_fIQ! zFdtDYRT$0hHN#}qcbz44+HT$LiZ}>*W@Jn_u!wNMch97P0QRAAApl>cEg&SGk3)Q6 z)?dLV3XLQ_5;m+Dn%%L)ycY_K^S}0#?TZNrFimY*MZa&aj%4DBPzK!iQ&ipqxvs`r zt*T^E#bz~ZGB?L3`1_l^^`sS^Q1rbn`Ina(Sz!z6_eV%=kO}wo01?oKae@?wYO=`} zJp%35+^1l0Hop{Dz)ynd%b)uKyARv3kBb+(6&|<>7dZ;21#lOwfilja?UaA&EAaJi zKJc-}N-jmc^Wg4&sg?5z$mAO=^azfC<&ZWt3;c~P!=DR4cl!+bh?X(mpXPRY1A`h}p+d(D1=<0tMbW7g@R zp0ISG-p(wm9fn42`Z3cXZH^U3XS}#(3D29OHDJT~6MnX$-YB&%*lq3sdpGuY$M_5; zh@>=E%f2Qj=Ynde@B&nK-+8?1osYiIv-3Jbe}nLKpC&9I;yYRH z{)E>V&RL%q4&4^cyPsrYKQNFf@_z*V__}14Fji=@M76wpur~^UF8qP~CTw2jMO(J# zw(xi=8{7Ir2AjFZ=o6q*ANa;$e~_WA>O?!xpBVnvD~aD{QZz=f{v`geJih{D5-}Z3 z%ZLpR2f7%%&@|pGfb3)_5^OcJJ~i$4Ty_%|VC+Pc;VRW_+J%fgpouU&lBPLHFqf$L|BGLA z=yKQ2m^xnx9UXmUcD6+NOgR6DiGI`=Rl+EK3ej^09C2 zqT3<>e-<>GWwlTLWf+Ab$R}>-k0f}0FmF=Uti5C5{p$UO`mxG}5G31o^x>;of1fN( zcC3EE`+t(y8pFv;NgXJ&fuoP%LA2j0wCU!xO9Z2_|MCUkB``M`j0nMw%=^_BYL3U=+G=3Y7!&ALr; zRqq{ht7#-yCrlPA_7oG3pkMI#0VZ^joOn*p-WmhRN?jS6Bq*S@wCY=TlHK4!6~>4o z;NO(%@K?$4XCgr&}BS)yvHXx=Cbb>YkO(6T#qXdV&!wh7&=+n!D!0g=tWR2=K z{st*QTp#?%dcP3q*x{*BeC^?Mq@;{HCP8aC_W0><5Tw!5@6sYAf3fv)3;ydbFD2qh zJD2@0&o%DsV#8eJ?g7{%s$5^ zo3D;ovA|yDwdRJ4Z{Itonk-(SD#EV{35 zeds?-PlZTEH7Ac#dM^`@SiNCBD7E%{9AO)hcB#Gg_kP$#Oh;Z|A;79%xd1Ua+!SLI z==;XUvDxpXQTz2N;LRjlVw~{RU1)YZB~ZF-n`|DQ{&GL2=2#;vpB=! z{ngy;*TmN~xi0tX^TJNohbR1Q@YLMBKaVmMl6?-F*y%mC-NF=lK(ywK5AWa1(1u1| zy`X#8tjso);D6;;3{L@m<+-7KC26GztcO)6(b+eLJ3HSxEI0a&Am+%5@0tI2bNzml z^l98M&ozjz^G=y$Uovl$(6mvvN8PS12(^sO!*$9B^5oMhIdVR=eq^#_n(PFI5+joODIiRRZ;9WG6+U%CY?kqbT#HpB| z$H{xggx> z2?Z+o31Rwx5n^WafCAa1B38fR&UD;RVbuVX&T_Yew5`6QhQ-GF&%OW;G$sLv6z$j0 zraN7A~62hV}aLu=&{oOR_rehlN}0WFOdP zDh23!;IsTAfKfc-O0z@J?4n1ZV`LGt;k=;KBnt|*+x5HiUg4$;KDDLu{KfKxd9Ls3 zPB2>FMvJ7a=>>U9EGb|M31YQ{-yt-W$0qmptSBnFP0TGM89kQ48_ia$|I4zEcgYNG zXL7CrTOWX)xG3l~_R_?h^`P!URLOZfPi{boskNt(3>Th8*}{<{sJhl)jG`81@$#0@ zd@5(c(O6Sp-lrN$y3i{1(1gs+pfzFd`-CFimKlhMczmW{@Mufa*Ef^A2Yx|AL$zKX z9P^ub9MLw4*p=5)?>m{GAXj=pt1Yw5`+R15uMe+=UWfau=~+k`P7fSOzByJ&kQoaRF?3Y{IBqv>mMId9Kw-*e(?cUYPhGWMa=>H!pfYTK4~FsgcNmJKa$9mH z=cn~@t&L1O{B(>Y-JNtsjv7R8vt91LBzF`iknhL*ocnw9rL1&q!o}G>k^+k{Rde%E zcjyJtZ?l;u763Hfqz4YCx6}lFZ;#Jztmt;@KJBneOCk*pFW?3J<4uaLbtBQ%0hNIq z=H|>-1?nCy%Cy>gx6U_r5rYn28%+b3dyhzunf7kE9X&Iyuf^Uh3ZEAw#3hQ@rNy?z z`UQkCy0fuA2plh;?j2;ql8~Yt0jE8mf7WEzD{vVRYuhxT%kEW^*oUBEq4L>bg?}G$ zF(UEKq+1R4p*O5W$Fr1Y#?PQWEnW_%Uc7l^RF2OS#Sp7P`vb9@`+4f+Y3{t9@pn-4 zG9bC3C}y{)^9lEetF6a)LU5Gy)Gw>7!;?5U=<5&d?hH`Tx1_KH=0d0OfDuV1_xA!O zV3y3b4r;_)wHK0mZG@eYQ)SBlHH8}p}ZkpkP%@HkGOlgq}eU9atDtb=xqAld?UZlA7&`dB71f7ur0rT zVipK8+>(->Bt(znzIA!JB_WF8n)5i($FRpG&lPULe3irdL9z<=?MHd8ijEtSfia)Y zc45n@lR;{CyS^;xIkTsf*rmQ`7%xZ(oyv|cEH zO-$rps!to?)lXYZGK?H<7Pv%mJ5L+XM0b(a%LjVeaRiz@S0J(}xlJ`(xM> za&{|Nj59yGo2#fOj^#8#N4p`Ra`l$4<1#@z^|rdwx!*mjXdPi$9f||wjy}q=`UT5G z*%>iXu?p)~C*TGY$F0Lm=@=xQEEZoWH?wLY<OqY5R(DCLZ{JVpZnBX1guDl6)zvchQyBssW18TcFUbRh8QBr3bG6>BoZ|4i&Q}7W9OS;dj_>HhXbJ$yZyx3AMjllgg~)!-5d6U!s*B zmC;m`6f)9v)hf_~6B)UH=3@rZZdBxDC{oU_=fWpiD(3mcQLqBT-ePikc(VM?a&i>e zNJ8(==0q2JukcRBrLJ*NWGuvpqTm4zrzcLok*X%58`Bk$_odHyC%Ew7c`CO`CEemnUMMQXR8eTP*n4;D z7R=l}w2iy{!%c@1&x)_B10kWj?W@yszr?X^l;ifsJKiU9gA9-32GbupO2a>}iv&-| zE}?n`Ga&i@%0_zY|EDRljp*X9_^0vlKgT5|o9c_dEfjbmE*cQ+$jF@H|1a|k``;$k|I<|YZw2rYb?VoDDqL_eWdFa5k(ry5DOcQ?eH+8L zwA5;Gc3i-PEkvo^a=I(S(!buz#MQsFRXIu7<)Hk=!S}T+Ywp zZtYqEs=M2@-tjJZBQ;gF+VyY$daVyX9J0LRBBqzBV&F>NTiDGYhUBHN zG_SdC!w-91!PpNwLq%!`3DY0BK6EZ$6jHukq{Px}sSAR%aJKYQAg1k8DVY+&jDbrg&TY7>za z4%2313B_VknWE6Q!ok0(2vf8@YMH}9^@mGh%v^~nNt zkF|rftDoV7BHrl(PeVwAEYoYwifBU3&c^g_Jz~2*3}q`P`m8ak9!rvuP0bUwFr1mc zb!mcz-<+M_v?DBh$dFS2 zs&41O-^HP>)3=BfdC`Zo&}fU^2;KbTyCt<*gj&WdhiAMix5Ed!p&TC#1Fg=E-@1<6 zkKYIt+})-(n?)J%y?bz|W{A|F7iYIKOu=Z=687QK6{PdQ{^Bjn4k3*al=|UBhS)?oc&sowe{t} zsC(u$l{+70^bbro8|}CJ1X)lfew*J9k15nJm1HdCljsT51X#n4#5=y>ZC9>C-eKaP z74S}ooek2Z>bV4wLig>m2xtuCbGrK(kR-F+DKS^r(Lsh^Cls@Mw%+O4tc^Q+w+v-E zu^hoX;8E{#^cv^Pu!}}}*0#}!=f>4Bdw0sK#j8Up6r%0w9i&vp6ZNJOHu8&lMsPeT zuJg^wy3u`WkedP6iFy;s!Anx+ZtFZ>Ia|bpIA1~iytndn;5oR` zNi!3Vx3Sj46N`OCjZfd709FbGgd&h6Q+ zh7AWBNc$97(T$E5rv|frgkFB4L>rTz7H$8lwJ!bLtX9_}>S{Z$-h>_#jHhS#>Cn}t zXz&Ha?HJ-#Iy>CrG}|1Vn4HDsu{XN2L9u{Rf^Av--vXdX;wfxF0RcqQ{DRDnA3S&P zn)i0g?x7GGOo4__sKbvv-@7-M;t@>;ty~vET>8U3xwyY!B8ZC1!fGuEA_q7+zGICV zF2I)=-t*^?^#Y?E_g21FwXgwTXG>h=7%ll?_Xgmr598s{uERh!EOVKWSa>-vQgiM# zV`xH~4U=7HxIdwOJf?X~LUZ;5nh>;q;9-e}c$X+UY#S0qciMtc}GT;9d1SUU%bp)bbd2%SN~}?uM?nCr+HD4BHE-Mk4L= zE%o^Wc}9yzJwWMa`Cb~xu0DJg7@8>qc1oQO;^zzStci7}hW4HEB<~*HN(C)+dUHjp zcMPYYYkSyS(3P(&Nnig&2cn_bpc$X*lMV@*<><}P>y9IiG)^tNn>N?@YjqSnhsQp< zB}w(Lb{%x>abL)n3>CaMm)cuoA|hN&hBS@Y_>n53$Rhc zc(q9KKK!M}NQz>rs2O)?z@^Os{zqJ%o~;o4>*H<50Bct%Wzpu^ctn67^+b4eMk z+5Li1jZfEL^{7MnE+*`mSg(UC{T;~M8EEQ!-eXXjm@WJqw25ubgRh%5G&yr}jM}S@ z+41_rf?7a%lvN>`<7VFXt$37$#a^gE(8Ymg6n@+tX5vtT(e_+cpC9yzW@Qs!7pdX= zNoZwcPbR|CK$zu^&xzoN?F{kX&r33p`MmYqLyfP=k{T568Fj`RckAV25sN-hCRJ_P z+960dzGWfmWk*R31B3;6wJc6oMfxBxk%yQ&Ur#Ek*{+TABt(9I`{||Ii>6y}kAC46 z?|Bgl5_5{jYrHyZUm|0EONK3nrUwF$#QS7*w(9b|GynLOjHr3lpsWJ ze*O982M#>tuUJ?wgAE$L9#e_b>3lNvmLkT9&}jcI#%*g`U8B2G9dqin31$bF6F)Wx z4)aMa7~sFo%BP55XGgN-$NnXh(Uo~TaP)oS%XfSXh?G6A{NF1f%(zI+Vo!#gOMuYN zfPCTM(FW%gM9XU%ODS@XG^0gaoKvCS`(>ND~=o#&2F$OdnJ11?KP zaTtAQuqh%5CdnVmByH`M-=qDPEfuu{14tnQ<|&)8@1uIdylX!*i%`%b#)6{3^-o?r zY@Uu%pZ&b8c$n;##`=q3qccU?ns@iAfn1!#R2a#K%npWIfaNbET{ZMuf4IF^jtBr= ztnJCxFvKfe7BkV}19TLnJ*$FCVLD%r0_Z*f=K3bL01@KRCT7ihH>x0KR+=H6-p9c9 z48=IN9;A)Q@jN2tP(`r2LH*)@79dx^nqY855T4fDlA4T^fFb#D61NN0R{?U=z+l9v0k`^*EMrc9o<7=tU2Q!$J;FV@@s!nF$ zJo~42CVdGC7n8ex040*+QZ2xXvkcs*As5YX7vAd#6R%hjgT)9}dcDTTLh^P|W=VOe zyx$#3Z07O?ROi49&XM^o;W)*g&}aFRK#?Q8?gMC(aJ)#4!1S_=S?7g z!@j8+SHm=+^EWNUp#TsSi@OcaVn=sb95HIGyE;~+x{XO+11`o*Q1@m|Req4B@_^%b zo#D@Xo&|X3#+8eG=_DJ=oB{6PoK-#zc1yD4YmryK^ z_93*2QUmC5cm}82n-WGuy7wky(|aEGJ8IG)s>=IlH8!(u?-xx0hg)nZ0`%%dp?~cj zwAss7^PEhl@)g7cgXbMaxK53iCdTt;Y^OTi5j*{y(D@{?M|{8_2XPrqjfEaR8*Wi( z&%}?oj1fpUoTV5lM#M27S7p)H z*b1f|iyN5=gikj)pPt-*gZ6?Bfo1b-tqQacHB!KTC^w&?3VGpfnp!{}k z>Ipk|B%7s~H;@sZC-9Pj=_O{ZlQQ07Ux7+;;g-h$?*|RFj5iw%w(qNb-A<13nJUkN zxMphT%Y(#vyz*4V^*$&UCS5*+CbLnx3o6sHIch7mVA_IDON(we)B_Rh?>tF`>Ozw#~)Gu%TTlaPy}x`IReX2o#ygSw2`lbfDLQ#d7|c8Xq> ze8XK+G5y@c;m%0&$!2|BKO~As5zgwm+tuOIR<-ZhaB{Ylo}D%jRHO1jAk-6bVSfLt z%r{tGZZ!RqmT1$ifrHa=UO&d6iEdE!YCti=3RGu`<>%{w%yfdu>SDrxN@ez?D%N({ z-Ekcl%02mEF*WmLh~vslf0tp;mwDkV4<}?yM(f@|8iTFgi*1TjB7w=C5t(c_ za$(nTKUABdogO?91dYLPV{fQ>n)GD_a3ZiJRySMbd!qLUgnB@xiXKj|w1&X%c(NCJdJZiL$7`58<+3VE%l5(!GA74qeyC?i0Ws{MB z(A{y5^loa}mvdg9I|MS#+CR@x>v?8)j>~LogAN*)S5C;52K)+5PGSVdQ0r}m(Iq(M zi7Tg_Qccbdmo0OigKd$xy>>ixILqSMK~$6T-M5*13xIPP&k~XzMXtOnHmMsPSEs+a z_u$jv&sOq89y?zBXKDO_Oa-U8w!Rxq-3d@0i#sA6}}TwT6-co^VOV>KE{2_d;M? zAF7bu??CTj5Wn(7)7coZ)x{>JdR_A$&B3fF$I_ewiNQTbbUmb(7V1!Xk%h{V+a-7c%A8FK`wG%PqomwJ)2&P&|!RCjnqt#OE=_ z0Yjqnf$`U%&EBwJ3&4$Pmga0&BHvF1JqKPkt1C&jo-gi%s;LU+M|+%?y@yIxC{&86 zhDI-Ppo~kama^%5iJn-rG(*zlAUxxzM>+o6EjO~@dL7S)=Fy7b{*$VGTRzb>5e4UY zne_j~++T*pxddCFa0m$`L4!NN-QAPm?(QzZ-3h_n-9mypgS$J-;O-h+2G{S+K4ebCJ1OA7e; zf+8<5vIzdmEZTYB`iW%^H+mr4c8z-iyxUK|Ry2#3-qy!m>;x;9ja_@J6(DU-uFPfOZWQ&tgS&5P^vNVF|W$`s0 z4t*+)QX^+=(m}yG7aqyr4@MMlJ)e8ZOm-LgA}jbDa4Pc--h01@yC9yo$a_z*jWnGN zLs+dBzi4@N8}O#`Qe~73qg}+qKipCzjhfuql}H*SRM|uxSjlOpLPGDqva=S1dRz3u z&sW!^*@VDT7ZG+fmgp=ab9rEL$lxpX-edA9$8iAwBRgd%eLd76ix)ob(sL$t*U* z76o%AuTkHNe_8#P3-D)NUKq-V*NoH;N$+fBF*Rw1^U5ux^5U`4LW$@ zn{l6P9&SJ`kdFilrZPnO(z1$_dOh9O%|#XEW{$GR-%{$TO#SfLg0bT^-L@R?QW>$I zw@oH}EaYiDmlQ8mlVDNMJG8BIYvy`}V#BdzvRlD%^II+U-<+yN5 zFcEYoo&)-TI>JW(5*G%C9KxfYwhQt=!STZln%3Myv?a#26Aq9&sZ;^z?HBxnB7Ba` zs1Rf!iX<}mc{5uNhNd06Rp4TC8uZo6Ovx`}%pa^)7ZWcJCPsNq9Mn80ru5d#VA#wE zGTgu?0Cn9cbvs#wd0Tc%I=xspRbY#_R8C7(z^P>Q$)%#~YrlD$?E5Fp>8RmfC&#n0 z42HXiNIz&uiEZ1C#pfH#gKX)7?yfKs%@LoqdQ#FywjJvDs~lNMIZw79CG%BG+?kKx zmD|`jQ&|s3fQE)7Jhy(NC(0ZT#wDtVJ8%=e;YG2pDvyfg3X2En#OvCPqNOJ%42)`8 z_S(QRezmr--Lp`K_d>b8I1~0WUNOS1HeP8XbWKba7-J_2jd%N*a^jC8h!|;%UYD+c zhhptoxw~~lS3aC8y^OIF zy!dMvSC_Z%C|EmRg^Y;$Dk6*C9Y`|%>j0@@D6Ku#=I4`Tr$JQ!5hqUhb7H_)%fhmA zXuTkpm+R5`^Sq)?u)mG=Wj!GU>IVmRs4M3wvAm*{pk%!)IZii-fnSgcdC$RV#cNY-9eRD|D6n`wx& zdVY}TiK*`-Y_Pm<6VxyDH(cs9`uMe)`u$Yr2Eh@F4WMKb(3L!r(^r<3!2Fn>XmW3# z4hK++Hc7`0DTki=9eRJWbmx95pbFX^ZMc4Neefo4S|;yy=+4DSHuZ-I?g<*%>9R~8 zP<F~4Ohup+_&J+wH5O!v`#%hXH-wNB2g#A!sbO0)yI3klZ_mtA$( z&;hi-9}d5nRz{nc80GLJMw{CXjB2>)ihJeC-X zZTgX{zIQ2WP-)e#BHM|mr&h*WyOilm0o=>B$PGtk6C~W6XXN!+omt6W|41N6&z%}y zj9bUYcRC|R%cg}c&4+OnDpdOHWuzAP@8ci_8L>PZ<8LyvAj0yOE)sF0>2+v;CUF~fy~dbjPv6-@PltkJ3)o=1D@={J*uHgNa_1G*S}uB+>b^rPlV zj0ql~H}jl-bqNFZot4!T$4pbQ!SmfFM_b?4?F|;OPNtn5TPX<#>ir(uf%D;SGFQnD z2BLO?5h&vf$=!Xd)O$KNm|2h{h6j7?f@8)Wcr{?B*qx331Ei9_|8`IWCK)H%b&JG`8{d0`-2_x*waJ7f< z@tY@stRtJlfwTPhjf=SK^ze`GCT3PcOt)Lx?f8f`J2zZ;d*BxKiI$6t^KQLUSppIh z5v3wn<*myw$q3*ZMy~of^|S-S<_@U>7y36|p8G(WTmTeSp_}|zGTGxrTl01e>vcO=+{=tg ztlsY4$Z*zF&zA(W;Y#xEx};bX);wok1XQ*w?hH6@QXsOPVrYz1fi_%sK}{Gfa?ASU z1SEz)=)vw^oo3bE3;K7ZGWq{u_7U?;*y7cnnuv=BUNnF7HrgOy6mX(V0q1}RqMzC> z%l5r59yK#LO1^`AfWYjY>N_IoA&HwW2p{5lYId0YJ21wEb>1Z~Njmuq%J30 zNUn9D?K|wI)3iEk!TE?je3B%?C35i_pR8`&Tnfe4Hg@Z88=uW1)b_PG4d;CQV39dQ%V%dqw@uud`!r~ae%-`_4 zAsWg+*Z>;91Es-0VJP69`7$+|Rpx%hyfMd%u=qauWNoY`hH>-RbctsfJE-CK<-eBS z#j~`x>~%M(S-BDZ-Dmxx?&HS#7W4O^VOp5Kl3b5T3dTY2OgG*ddOkZQ|XQ}N1;fAAW}5++0s-(wx-%(9 zlOU;&ZkeYgLrmMW%n%}qvKUhS`h22Ky{Tbo%71Ov|7nkIlTnIEkHB2JQc_b_n#st1 zOl$90TN|#@MZ{O^=`D$}=5~+W4G=)Y*X?dXkS~PjbzNj-G#whS6$>VGettEQ0%gC^kwRznmxOiq+qv|>idW=g&wNF>`jlI$&plTy5Fe7iC!SHz2*Nd zroA>`fY>W}hHlD!NwK;4frU*fO~{Y6=&yy~p1!VxJAIV3ro z$D3`fN-U7wcOT{UfA;+mh5_br`>-cdOuhnp{;9EzNJ%+f;v&0|A!JH2eoefjCt}25 z84aN3Ud1OL_3SwqP;GK6v8M4Dv+DZ4k#B8{pvrNN=Ae7xMjx<>&*&^7(QN#_ zJxba?hn%}{#+WSF5eO^Z+-R}t48~XO?|xge|E|(NbIbLl^^{q2h-h=;Q&t5;HApITztv(xB z;E-dh*?0Y5qY*$Q?@9VZz=gx>NT5GDX1du=Xuar@2!3a>z02yl%}j|%M={0L*vv;0 zgzIFkte`QvI0m4!eX^4?1vNczZ8gUz|Os+iCJe#7ESpH8zJ(ba+!&T3Z=?lcs9>i10H0K@73f zWO7g{oUJt=F40CoOMT$Zj0m`?jl9jW$~uK9DXhjUL0w~bkwMm4U|#l3LS*wsBtB21 z!fH5d9@R+&d!O_^-oxL+Eq6u8-4Bn&W1St4Vh8}x&S z3TkQc@guKfKvJcRn;`3cK)`p$hN0FOu1W?Qy%2-V!Gyt>&gq;N9{*5=VSBV@Z*zpk zV9B3onMczkzqxZKx7L3H(o}(P$0U z*7!gcxZ#+Pm?$Eq2A3u{@S=(Et4naP<$fPQB(!&P9_JM|f!wklF>c!acAm!zit+@` z3gL?LRnWU&V{&@@j4r&!WunKSArsU5giX$8h!*O}X>MCf4nV%PUncUNd==6YG`B}4 zKo+p9(g0@t7aanh&yaK(hoGaxQR*IY^^1M!z6vv zD5ZJySNhn*uEdKyyIBvGt1USUEm{j+c^SXIoHZkEzQ<3Q6aQk1T$f}TS;CNS^+zEX z^TFYd_y6Su-nFa}P%I1xS^O_c$igD8CWwN`)}$|(u*~K?v&lBISxm*RdgcJ~2H2ig zKuL~&To_s*P^L9EIID+ECZ@t{JoyHks`F*{g^~jVr_o{Z7GkqJc28(S&We!A(jFaF z7i4mmY4F`pn4iBhuBW_Avmq^s@1DAdXt;NRjK>RXQ8Ecs9E)X7{VB8c&uQtnxN4q1 z|4>8^VRPD6puJE!;~g{RsKWVUYrF?uq1SJSfK_893q~@W9Zk#R;3S5;?8=6^UM#cG zY1Ftd9j1Fp&=L)gR;xyqjgpPn7^NC4VNDnagG-{J$)A`p9}$E8SlR4W!{_V`?Y_Gc{&qWE2-%CA^rPgAsIlAn@O(CxqS?aq^)7G0 zd;j7*k+SLhj=ym=GhhKLP9o60D5W2`gZtPYsn&d(&8r`=g4Yi5uEK9q*J7#P?xi-f zZwbXXIdc0z+MKzG9=2m30P-~ZiSc6uDx$dMQd?LD|0St(G;dJ_aSyhj3-50bhe^Sp z_~z?>fc*cul5Jww@DNvrYdbBl-^;V8D_)S!^?pQ?qxXqd1{LG#NR8WboPO)F>`7>` z_fz;3PTWIGp;}nI&EqDQe9a&G$T%mgvzeHvg7r4%)EZ%H{kzv4J|+TDD>OP+r~2Co zs;f6D0R`AE!((n-;|cm>bvZmKZ#ni)ZHk60=sI4`3Hd?zB?aJJ>6Ed&dx5}|Hd!WU zjSz#O?6<@wZ2i6{^OS_k>}#RU#l4)JYpMqOPSrlQ=VR90-6rSjFzL33R-)Y@4dG%PN7?$WcFvZ>kVZv^m0%%~!n z18Rv-)~P;EKzOZNOxv%lvB!;QDtBwQA08>bKPs~nZ{>-l_pUh}ciSn-c+6obl51ba+duv1uE&c+)yeETzHT-z=rgk`&(23oYsX-y=U)%np&*L^+h_c0a%D|9>%>W#|c?Ka_R9R zZs*ZTl1Ql89;e++i(+~xd@s4iy`j$%TX$If1>2wSv)T$qySM0%)g`R+P9KQ!<6RAI z!X4NL4n2hPY|X8V%41tZ@a6nP)&M@Xw@jL`isWSMbxZTOey zh~{ke7)4HdDCBv{e`Q_V=1(t=j`_f!wr?CAk5g8@XF&{Lw~oa!lahmB`O-IrkOaAdX7+v zr06M0RgDqBd{Y$R1_31!6Xlf#vzhy3nxG%@gEsNrYDZh|?Z>yH_bNJS7 ziR3%cji1TK9b3MB5GFE|WUGgP1wDBP#1L0;;OS-onNj;qrgHj*H_w_W6r|p`ry8<= zojFR8Fg)2&VN56AULPPgu%<007_Hb@yCud--EiZjJx#!s0J?K~L)=(jf zcmT|*pM=QL8~-sjxBnPjkCZN6@iufQL1HJ^8V$@SHiR$h#q{1n<+28EL24&YdrC&Q zdV8+5RYyVU8j76$(tFXl&UR|Wb%tayOd6t7UX8(qRGIx8=xD92CYW^f&Su`aTa)?x zpnCs<1i8KC>Qj@XTnKmva(37u*j@SZ{HdX%y=5S~Fn2R|l+TiMYpm|^uG$87tuOj` zb0{R)Fp?O8%NC*-OH(u39LM*3$KBDi<>2eKxAk}e9=N>|(ld8bHd>Qj6c41?8{Nt@ zK(A!<&BBzuNBy@P`qxEY_9VF?+wpe<+pusyl;NtJFqQwITBzP&SOs(qLySL`7a1%M zTG4{oDt`{*a;C9;OFkdTXS(Rk#??`nyy37xI`p_zjX`H3?)&p)VdaI$uEKaI9hq_z zS9+u6>FR6WDE~LCn@0m0JKIGti*WE17scFYgq^jyv@#7>CR_YCA5B~HSXoS3Em!Y3 z>=nPm9$_t2#k!E3jLoSfi~Xc~w1)?wpWh~rnm$J)i)DDJ%ND|8X?-YE4tF4R(x!~sei;G(m>iBD5(fg^!j0RT zcqbiRRCIGQEa#1^^gdYsJ!SyxQO~}_yH?w@Ru%h;tg`5^v-lgd`N{UQx(XW z8XJ-DE5vvYQD%yNT`leUKBV!IDk3y!xarU4$nEk_zQF45TF2Me$bP|ItBYg%${`6$ zheh1x18{1`^T7glU*$&mZhzG@Fs?hTc?Oq-4cK4o)OhUYidsiiI@*kJba|Ib!;+n9h6j zh2(AO!>U~=Dovxz7bO$kF_s!Xnx?d7RV|eo4I6|LX?GQ<*Kf#`?AJ|}M;ESvaC{$M ziK$*nDW)6tk3Ny#K#mu$9R1#pKKTg5>-L`~(EB#kqzQ}>!Ai^e;Qin2QZ#cK@5<0( z+?(MeCQJPX%F*G%=Cgn4Jfr^u4<30>;7hiMJ}-N2gLgT8FL|!%%sL zn{O;|Q3PPg0c7*#Y0UfCxF(H_CWZ^!Rl($Fx6)0p=Z{@BBz3Ue4l9>-E$=sr zoHA9FyxfS}(gGR^D|4po{qJ)`31^Vu%;B=vOX(32Z{>SPmmAOx3k4VVHkB z+YUcF+hcBtAsee$2KVNq$y#!MUz+%e=t;S^cr%XoE;fmf;@GXl!PV9?;elvP(xjJN z(Ch14x)Z<9LTy-#ImEqDWB3}M4I{n9X^EXcRPo%o{TeW#hpR}rhwe_9`!y6z>H1Dxe>K!P0sv3ghf zTWSWv!o__t<~BdE_yG|ZWILt|3J7t$7*f`3w-JbFXh1_W;e{RVWbMK6)lO&qj|mUp zOddzv;4h!X*<|M+$Y^Zu(kWqj@@HJUd};VYoeEPnwzlxc0fMTwISd(mVuI;_WdzmW z7~yChT7rOfhP^B-B)Vrlfv2$bRQ^DwQKLYzN?wmvruXbj2cBsR)3g1HbMG5LpA}Ob zj+Wr?Ys}@RBP%=si^azDkXiQ4+jSnsimlCpCjlR8>rLP9pL4VgJ~F?4V~uYvG*ot5 zfPFh5%XBF*f0rF#EYftgIMQU%0bJRa!8tHc_0_WeG!pgF+j>cGoe(O30*^Acws#sG zu}4V#anI0;u+gmf|2a)oTrX_7ps%?^e)qcd8Mle0H&fl`DW-1kTn6Ho_6lo3zb2^ghJS4rt75ZasL-h204~fI`Dhe4oZ{NdYA!ab_N+3t zNW=~kQn9D&D`&)_Jnr}@x@zp7wah^C(lvWwesWLysbAOHV#H`Pl=@2{o#7u|qOMk2 z!TUOhgJqqA!jARn{9wI%g4)eh^oeBL>@=wfked!>fKqXcq$ zKZ5$-blPKy17v}Pnoa*55~w?dWqmkV%IWwmdMm+?B2 ztA>4S4hra3WZab=YBbP*i=J954RKOaR~FVPD6%MbVH`uwgRl78crwnFrD#T`;1xxp z`6~`5CnhG^xLnB5x|k6$M-4mImQoLW!#0I6h=1Lp_JvRjiky>#qj+?j#_f5yXW!&L zJ(6+!r6;h<%0SO}v;T$;=8;s6_CPPS%AMSxu}C43^j%Rb*nWbZ9b?ML#c>gzZ;^qp z8?CR0BM=6WPWGNwR`{O|82Nw4C&b9+Fwo+1X7TiAwbt4q)KDd|eFEK3Y6~u@Rc!i; zaN=9xdt7!=(O53XPGzH_fc?+B(qW|?D1M@4>7ODEp|79EQWuHK?g|8j*( zggeOimAV?rPxkoT*S`YNSc~G#Q#ytNGUPT7a*LO?mF7}A7tSgD+%0&C)7YY<;W?GL zU1)v{`{CXB!-O+Q*Abi>^bnxT+hLxS2`A9MYceL=AFEGNv zh+QChOt4|6i>}Tb1;z(U12P|=<#GBDjv~1>a>Y+DK!Srv6j;Q+nV=_+1qd+|C8?$$y|DNY9 z<^a^rxVgT_Fr9r|HFy4@J8bn4i_k1VUcdoXt4~h z1j}YU%nO_O^w6pJ)z5&dsN-7vyTnvk>xh`0$C^UcPiXG&T&&=WK03|Tf~4heX@Q_4qDoS?fd4Tf`*~R8?d8`T&yPCz#)Yz`7e(GPqoj@^AA-J${8rpN=N>Xqdh3XD&W|$Z!tpb% z78VZzZO&1{l*A^hI5g5sj(435Ic#2$)U9KQXA}fZ2xw|*(jxBn)Z55RO$&dIuRhIn z6-8$ERgAn`^QyI)p-raO{OaTch4-ygqI-<)4f)CsA>-rAaM;^3@ZF}t!I|CY#R)R4KFbqDU^+~&D5ol9dVC_rOstG*I z*6t;gkKDMQqGcZ3Nu;aTzLoxjTJ`SDk3ce*Rmqfc52zNAmlX>>T;^ayL5hiY7H%}_ z(`5qgbB%b@@qTV(NvfRb^(qrwM5@m~u&N=h+uWowIdI?Dn4=->0P zkuLDxEz`qMhUWbc-@GmnCTAD{v7a;I9!5_~;r4}?;I&XQ-roo;HaSt%)zty_QoH(9 z2o>dIS!qX4=jnQR@dX71)z;O~Sh`WGfSWR3Ja)t%x6cbhvCPiH5<=o0h*lxMDF>e$ zp>BavSRI$Aw=zR(FA0@EBE@~!s$14_EcyH-zW|)<#1&!aWcP5Ja$_tdZjL%_#WNqy zY|;^IxOf#rY}7rI;>m!)qIn*sba>R{ zQNsu01l%XFI79sQG)??q@#9vjbB9=Y6f%C@#=>3^tHumI8ws2E`JncNTIhJWOW8O) zd=Xl%JDp7x--I10uAi#6(U}t{t7s!WT|nENhUkqX&1CUA&j~NzZ)+X!uIW-tHGhM> zS#{vzVv=+0PQpGre;)*Y1sx#vBT&!ch(4l#-fhY<)ienVwJfO4?pqt32e_S=-{BV% zxe??vTk+<@UuBtkZ+zQhW}6?>b$d)$!nV!t^WdUbuQq?MvhCPcJ6YB1Rh=6(wv~l} zFMIvkLq=!=qe8$2Rr}e6>&4^L@xb_$u`{8(#eI9$>vrqM3Sy=s-dbbchjLxixZkE{ zD*$DSbPVLMI69bOu4EYn|xC|MNR-;ny!ZH2e|>F%y6aXSQs zb_>t0-25rr^zo$O=FA(EKElKo5Mi#8;8z8Gzrk-+GE9Az;l2@PuAxDkS4$nz+DbqQ z4<#Dnv+E6_S2spE!vXbz6aL)(@&I~!MKx_wI{~4JFr{yy`uzWLhqKthYugv z-#ew+>taKo?}BPWYVu-G)^0d%lWGI>)@~dK#DTQB|GvjX_iJwK0g5C(alOr<44))j zoP-57%7Wcf?sjBef~Uc|PdJDrpYQhtwCb!d0c}>|MYV$B8CUU=?(VNvR#w#X^!(Np zO>2d6j&x!Ucd8#t^xVVvh&&Qs^q#S>!MJ084*U`Eb>vLHH12V^zdvxB0XZDXt!gzS zi)ZW0TCcwmyg6UUWNk{{JmYKqE`jR=;Y;}O%jm>oUDWn*Ma&FB07?89fWzYci39dx zUvtN!H$7v%%98Go)7EI?8=c0g(x9bzR$o)0oS{lr%eykesk_TM#gZKNI6wZgSJLXy z+egOYETHCiLsiVg-OJ`ExyUR&tA$2WzEZWy&A7K2gLr%ihY*2i%`MtNuaKOs&l3jV zwsnGGTH3~)oET`<)i-X_UG8XH!O--Q4{#|vm$a}cv%y-N)~kK#9ETcb!+7<9aE{NW zd-mYWYD7dbQqoDL{A_ktch5r?GhRx?7o@dL`V^_WJ6qmw+);;XkhY(5-D#Zu)- zEse#rODs>ne)m>05=W;i7Ub>N15@@LrXnIsW_)sTxSyeAe)^sA-sq+_m7Ix^Ebd*d z+fp?vH4b+?l!?I{5PbJIs>Z(SVJO9AuZ`bG>Py@eeHTJcKQ$oR+`DyrRAIAT&TvJ3 zQOf<2Udrt?%nX-g()RGA;55R0lBirnpw&}~ptq4tmA$^d7lEUw+Wj-0-?0bl%Sh)H zfBZT3n5^!Nf$}#ZsvKXqoK%5y2h|{x;!{BOD`a9_JwR`Wy=nrBG@g+Y1KaWE?YK$H zk=u49+c7z8`D${2rMZa6s?D14{esWF?!f6oN)nwqtLxFcuS=J!d1i7jZ*qHkrg=(h zUxqf`JbJ^q5A53aAMvdHF(roJQJPT#H7Rzc2#NJ^7k2?F$+Gewq*C?sqhCq%S~Ur> zNRr+N-YAZazY&RahTadz?F1T!uzg|@alKX86%znRcQ#)2HS2wSt+hr7rS%+Bsb|e6 z1;jrcKT~XpqwMvjp{H@@rCQhqj*}d%@eI8o1X4A*9>Bo;p+Bz^S~ zNjPRkd0bfwWpKYb$fcIW@}`nn-Nu0Zm4Ofj$hWDes?xwXrvhdTU_>>wWXiETh&gYZ z#QKBahP?*5#iU!A(b9aqEH{B#7LyMU1~;1-0TA*R89u~IkW*7rEBH$g193L+D~XLC zHSQtGcLnOaYf;ZL{umS1u+xV{-zMU<-(II}e-|%ahEnK^cNNMHz!FsM3ouAZfL&c# zxu>`=TS``T%+TpLWM$=@7>F8IW31JGW|Z$V;N{NjlZdS$O@dk0V4fzG?>h4Qp=1Fr@Yh!yH+id9*) z-jnQ8bDH=ij$=mYikSE{D_!s3e-sp}th|&vBMyHaXg_VT%c0aI=3eQ@Zx_0<6Zcxv zl>Eyfh|>eAz@#_MDK}scJpl50OD+v@;JOSH-jd)hVfHZF>#A!nOKKI*u!bW^4nX+< z2MfUQYau0@NHr(v=G%8~UP~Piz3pz?HbP&{$b&ueCx;_^BRT1^S`V{gp0`-P;$!yU z6;(5xw)&9$`_F@5vgt=eH~@ey)wc{x`+t5l=i)$6IFNQeWP^nP>z#*=TU$j8| zcWmrga_JGDU4!GQ&6OasUIN#nS!7C%$`!(f?2^i8Twc#@3_%}ZFkS0LA2 z$(@gV>KkZ(sgzXRm!&h^Hdw@gKoh5vYM+$r=)_;cBErhl&`IyzSfk4j%k;eZ&6hHF zfxxSv0QZ7?MQu2MA#2X0I!rD5ot`2kU2AIQbJLF`g zg#|GH43-1dFRaf9c))B1ov-*I#t+xWfU}X6MFQ?3D$2-Eocya8l9w|5yidAsBn+U6 zMZ?Qgwqt?;MMDYVVo%|OllbE2SIz}lCW%@*mAA3ZS0Uiq1lTM2tIvamKG-d2F2VlQ zZtt^B`C_jPnR6Oa7OvjC@rFO}&HZ`RM2g3oXj=+P9!sk-b(OGU& zHPzK6%*x8bz`}}8Nts(o83ThUu_9ckj+CmCd8sOal~`WZ`G9}`6l2}9#r5=vfHwns zGa(~GT2m93hlgin$qbo*J2pKXPfJ_d(!!z>$}bj)^96W(+6}hA-X>6GDO=R}>p8~O z#RBjov9Xg)4gX25m8=K-4^ThTosg6D1s^eSUXI5CA2Em>f1XDWRB(M{mO*5Dg>##o z!D+acAQ-cEijEL{SmkwNo6M*?oXns-I5J|q+~@!Z0>#Qu0?P}e_?GFwa86o=!8blq zQc~~W0&45)jh0+@qz>L4mmi=803-<8C=IPm4kmHV&^-@7uStKx7 zUS8g!%1SC6#Q2Yvaai&xZ}0m6fCS-} z>N%=uE%#;k7WAJ0(_6@yMnAC9Cnp>M0j|s@GOwIZ$ryWvINnz0+fu#j5AIgJxb>!6 zub0bJtQs$ZA73Wn2cQl<#E=^Y{*J@7>sd?>4-Z5l{?x}uZ#+Ca3tQWMz|5gLN_&eG z2}37$u__%LSP>I|2?35F*bo39lVo7v?g0X1Wktm=z;--7J_aWCT0ueKGc^V&@Ycme zDQ29!pFe*-w9anygrJ9s0J9tb(bLk>7L}Czs;Nl;jPpm=x?)4T#?n91R(ZI~dA!-A z0s}Jbl%nLu*6!JbKt6d+;>hgqi(ypcDztT}S(t@1t-s!}(Qi<|-e*;hYc2tX{i9jL zR@@=?3cktx=Tf_gBlz<(NlLWTf}uYXzhOcLwpy=dwSnit>bNZ-7EK_jtc>pB;sV4~ z>!p4d-G7P&XjAO_M@MzTv}Ra zbRY{8`7t@E)E`4E|Lq$cu1*CD>;0>9?%Vuy+tgia1 zj6tY@^Vk5;j4;)F^ZI~N@_v5&x;Wm!zV3zqUN&9QuDCEjS<-KYWK!EIKN6f5@BB|C zsrV$e_F7<0F3-){0`n%$$nR$SXBxAOUeR2btDqnp5getiWV6fRY_$i}OlImxZt$)h zf^XM4A&@M2C9Z@*ezH&#V!$ln;lTqK|B5*{{~(h=yT0n%93%ZmH{Zw%GA0fO*6lekYsc zqXZ&pV9ODgVB$39$16S&7E{~R41DTds(%d@7D zr^#Hq>mGCfS55+Zg&i-yt}bbJcbDiiP3k#6LTJF@-Wrn5OJ%qAZT{u~spk(g{dc*q z@;?p>u;@7#U7HvhpUrNE%o8eP4i?h=O<^Eyd}XCh{@X`gxX34NRjCvkgE+q8MB?fT z{fH7DnE<@m1N0=hswSFDK^?aW z)<8Ixm>>@^`8AIkcQg5-Kny@u*(Zme&mpG|e3s=uiCpenAZOt%x@CjL|E-se~ks-Q|2 z1#%VnY7$)d*5di`?N9(ejiHqQAx z*EK)q8bS5H{}+xj(W#DXnw6V`3KCjum%+d%{pAqhJwDBK9CFE}O%o}Wpq@rqU)fd{CPKxR7RfB&h#lD3Hscc3mDX+eJ_x7|{RfUoEs z;EP2(l?qj_xvD<$D0mkkf2?D=u(fz#RkRMhFZ#Q{{{!{%3a6V;{l7O$O(q;RH&&E} zxk+l1`~49BGRWJ+fU9;%c|F_SclIn)f`2 z|EL{g?_CuMMdw{pxL9{>G^1&%_b$2EMrMgFdh=_4HQZSDy>xo5eTJKNUN80WJ+M3Jo~~rSwq!e`2S4;R1-h9F$P2 zw6|dSRdsTP5CC}t4k|eDoPwVLC}~z4#+JoLz7GU3W*n6l;mLZYV%22;-z&eUgta{T z#E3=ViGD%_u9rN9)jdx>@VagH6UiPs_8ZaffhzkeeTCC zIQ}#5FOyw@sp4>xJ6df?k~n&6-Gd0IGn)rX{H-923QN+tn1xcRnflcV6qp#{1Ou@? zvO4a-OCve|x%e_xYItyC0{*tDzoCTho_I{;uMRHYtSu&WStqVte|ZY8GRW4C_-_hJ z;sS;*d>m zAgjas3Yarstk8i1(x7%jMv&yp`2X{+nf|;))7EQojzMK2#aUOx3G+2h*j*I?2iYvl_xVzO zkx2P3*pl5-1>FCs>pI;(si1&}hzrnR+Fltq_Wf&m0yx0&EzI#6+4usewWfyJE8$Yp zJhw4J91Z_h!2qVdJoh(TzY|Qyi*xqwIGjfoIA+{$%nq?kKk$<%5QCcn)uwB+Udzj7 z%`xt8_OQ2rYn3-E*7k4enobvM8(haNzv0^X?eaL_Wh_Zv9xiQ9tWHXaUnr=HAT!7^ z)bfarthid**%-9;KuT%NUdGSD_r7qwRXy_)H5H^1aTKS@Do(gJZpHW+K zY`IuzFu7*KD}4^u4nwg422*`CAwCxdCF(nimUkXr62`Yc z5mRTbXKZ+KYIKr}-+PTJO=8oN(U$vHO>v(1!{!4KkpHehNzhKT;)-u$+b}~>`K|Z ziwpv(P)`~^0=Rf6aAjtHF#Nk+s~;h1Pv-~okMz{th=D54@Z(JJt}Q7-ee!m`as8k! zL`a>*YE#!E*DxR`X`pbIuZFjvODPtpf-J{js$aRWVGU!cJ$!D?n(8C{ zPtR?QVAWkh+=p0B#?3;v9cYJsszlyg%7@_5jg+;sLGYbDQ?*Oq>-L+&LQ7osP{TVI ztp*$8H0{2*ikEkVs@f*v(82e_n^h<(&^ltBm?R$yqv^x4o$9-ov%MFu^c^alF*1Gb zEJe#+pSg2-z%*~G!Xp4>iY-c zTsOQno>={d2|{{e#_eHC)lbLE3pA7OZF@)lP23mK^4`HY`<$%SM_$R}sB=SBc= zgw$*NU3fvJNMn`Cj^C>%Qp=kI{SzbUnZ3K7ltM);_CMAO{Q-Vy5YU)|88S0-K-IUt z!{ufZs-;ClF$i}SLJUKHuh~O51)w0IWwk}r*F)tvTbyvV>KV1CHPUD=hV<57F1y7> z&?^|c4U{zo!|irY9@JP4ez2uwLiJuxm_Z{@m|ub@%9fOST?QfxnP2s)vAooKNyrI? z`5%9CKk{G6^j+|Xq(3rG`n5Fpg9_`c`#`KL6RiN8HuTa^^;&+o(@Ug#4~c zKKwkpczVy>7$3gEWkqS<&iO!UigRI0NDMrV0D{fKY=wzSLf=nKDyNxRM|$r?x5~Y9 zDm`Oe;n$@<;}gI_QA7P=C%(DKmQ=)$RPUUIY|m8jL)yD}@dBlF_Ub=kp2@B3^jTjfU1(C;22#s5@|Myj^0H7A&7YYzSzD^KOw8BOI2K@ZuR z0C}?9bR>=SmL2oA)nhTW`~dDfVI9^R81wT;)wk9dJ3Eui^wfDzmtsSaePjU5_V+#q z@&Es*dhe*FvhRI3HoyTy9He7FQ3R1r0E0n9no^`GD%DT~LX|23RHRoydK(czA~n*h zfFyKAsi6v?NGB9YAi#Tq^ZBmdJAcetGb<$bp0m%hpR#ka>Su8YZzdB%BJdTMl!fM* zjowb_q78ZI}M`rt+Yf@jo;_;QH>wYGa&2mi4=#T2}e)?2J2mZ}qkz(Vu9GZQi z<*VjMRZ+4(Oz*xQmYzDv_1 z6NwvN!Gj4C4u|GkG#7L(c;{p)5FM_zP4tK#E}eOOnAlQAP~j}|5N_O8zbp!2c zwZ0ch?^t@OPlDQs&0x z-t`vq>((3P^KQzPfA5T;g#wo9QkUjlP#1JJ35f0E4c^(Un=y!{oi*+C7Tt`Fb(Ofv zFAS+A4i0>zSmk49g)wt+pT$4KpZ)jcka1^(bHUTO>iCp~#nTPD`*2RL`E4x^2g*>f z)9lBM6!dZdx93Cv{m|h*flB^<$3L(6zWVyFU1UmsQ{c|cro)Cu9g)}a+)$lPnE`IX zEj@_fkTvw1slHw-HJwX`H6&Pij7c|#Zf0j_(m}J3|FqQXTudyQ=+ofQN!Qc3Ylw3f zn^$VwxypBN+kGzTsWVzL{oz5NIkbHoN;s zIg>JU6J6Xi2j|e8uKI4xR#fnGVl2#X`?1+?q+JxidO}bokq@!EJ=!%zx{G|L(1qP&0+Fsp>~eyizHB zHUmG0#OI65snB$W5v{W}Y|Y_NROM_splH zKUBIdO=ewjZ&noJ<(gXSu-L7)NqtX}On(_&pZ}&}QCHa*& z^59+D!mTWy`HB$a5E2^ho`7t;)wrWubFa7QljYB0ScT)?e}$YjPOMORSNZvD3;zTm zj94>cWo>skVQVpfEO<`y9Pm2te89kSY(taj919)aGz+|LI*Z$@@=f9O-wv6l2*#gg z(gJYxf=9M_$lO$H)-%SuXfcHCngJuMds|VLXmFQ0tXqwc*(s)&_+H@GmLIQDR%dTU2UlOnxpa47qBG^XgO~eR zv(iWoeD73GU#>yIsn#s>-qyxPI87+DlfmnH`RS0wn~Vg>-)ucnJ0Vw^- z+QXH^Cr%1g&Q31^DZMD-waEkLIi~j4dOphp3Vo(o!&_n=o#YC`rdU?buj5zKYf?fE zOVZTxUb3F}5;kKbfh~)@Ul_B-z8Mx_^Bnh0|M6fU|G6`)o=^Oc-XC5gCE!g`2Th3v*pY$SCfqO(-*Lgs7of~0o_fihn&8GFG5I{w_8}~ zLa%yHCN6fY$SlI)ylcn1YLgodkjNE_#r;G4v`y9&pR>zzztiT2JJQLLU*CwEc6AFK zWYT-~+6>+qzCX%voyS{R{*`m2cf4)I*J1C!N0ABXdXLpChc8;VGviLEwj{%?x$#jQ zA=!3soP5F(wE6B#7~dHXwtY^r`}?YmAoGq=m-B1Chu=8g^SWvNtTDs+C#D#E`zPB3 z`xl*L1t!_C(`EaKf{9A=@?KGyZEqGM* zP93iEGm{bQC9~dRWAeT=DqSv6_{8RE^$sq%s@D_Ueh*|=rmxHI#&2 ze{;h5yN1{NvvhdMBCxy%f!-1K{aN2rFP_HuH}0Qx<0pj$N!@imBJFQGb2xeDD?@(HAjwCvLf*1Q=N&SjiJt1Ui8j*!@+; zhlV!4e~A9N)koUmg zaARDHZ=3aC?;}ijg-N%I{ZZBm%z!@gQRaW-2hd+?~=gav^kDJzi z(6P%^d|9YAVru-UWs@LC*vHYaqaq}ICLjeW|8`3LdTc|5(c^!gzH@uL)nV6CacJtk zIJHbP;+}Z@yHX_nxP;G!RZ-P+c;N1YmEWb6u$8g(1##)AtzL=ME@#p{eVW8;x{4L# z$$MPYUY%cGo)=sucxT4Ud#orgt?bv2Q$>Q=th@r+B$*#>Eb z*>LDh`bWnie{i8G8>M6ZD+7_#;a>6tRgUmhhGpfATD!Nu$NZ!Qf}Dk3*?QkEP8Eue zu8nq9dN|~vw9(9VW}?>CN-#@f_-oAGaQUcYM8_wQk-fJJEEf8%Lgj^5RD_I5K05Jy zW_Nz?(IzUUkoQJ5#>qm(;JS9pwW~#4&Chpmuh#y)+MWH6#QArsGpVq!2Whxn!P)Px z>%)p940J#9+coaxaiAwBYny-Meeo1h`1sLKZHL{)>Z}1He7N))c&xiGs=%Q&Ln=1A zzERCghfCIUX>;N$!BkL!SC89`zxiim0-{VE@`w z^Fd4G*)m>}$(GT*=f^+_rEhSnY<;Edy(PEc=ycf%q3aNRn5U&cl#Yb&OPf$TP1$Bs z*dpPH4q{!z+9dzX{2}T)bH(aRn-;^62X}VQpm=#EOG&)yK>~iGWyfM!4>g4kYt?f z-B79@ zb8Kg!J%`_iHNwhaenKZ95Q%4)v1$}QW%}R&?qS2mdBk?UE@{O%VDFzKg^-KK6rCj+ z5AfiTnLFYAj@L?VHo^t^c8IAr;(p*uv|iu5`y=FK&_YW3w)y02^cT$T!TLR=7Dn5Q z-ahgA<_|H{z@>+)GkEhGX{A0P|J)km9Q7>Izi*`MKXt!HG2p6gW`F>cGAf?Dz4sCA z*du8Q-)!KM$TvTIi5CZ+4GMF=9;Wppbt}wj-XLA+o2E?2!nht61|)a#W8Gtj>!3{z|7^^YY!MuS_ADf_x}? zh7-eOSG4aoH+8K!a&q~1Dfir2o83K=5gc@0F_bN-R8CE*uHKp=cyG>a%^A_& z|08p4Xnjk{q<2(^Yjy2;YyM=?>fZ1NWs<;InUdGD)O8{ApGr2&i<@86(K9!6MT)K>YIB7-Kp>aUYBKNBLi zLo7L~Qtu~d5#co7PRk(X{N2=rGeeiy{`zM%WGf$zhW5$S9)>OhlkIiWKf8Hxl8EE4 zAki0$R|9tDS{mQ5JMCv>kvi2UpL*3st<<`g4V1pWuDtrv4XfSgJl(cKYW86&5Y1cN zmPOewa+6Un_B~QRoM#g0e%jpjG(9PEwrB2Dx|CqrGd-?RvqxV$nXIj3c4AHI&oezu zWjDR1!Auufkb@+o$sBj@|6&<(&-GF39`=;E1g8})k_)|X&;04`)&jkfkKv6sZ&g>u z_J>o8u#Thc(lL$SrdPr${}x+#-MSun8LsgaVJorx+)EKE_c>P2D5$`9!(-4BGF8NMTgL^e%esWWh5-&6q zD4mJeoStK7Pe+rcRO-c!j^`3Lm53D?4fGXAqW6VNVyxC?>N6uQmF%>twQ}vMm!sGO zb?A%ekL6-1Nv6BWWI-gUsF7>o2Ij&8C)V>P7=2uuL}0Cu={i!^-->kwnKwrVH~#(G zSwHROOM{-q*kZGrnIkJt2wVm#{1^S`8=Q-6*!56tO&|aw3G5ZB{N67PZG*1_hHfRM zG8&>oapD)%qgf7F-9EfwES68qnxx1T1>~n6^P%JGX09861@Sm1E0=x=H}*YV>$|5M z^Lx(o#+U>$2A=7_KG|6ua6li-!Cm0jIc1Qg5JX~Sh%OW$Zw8c>%sh{zyYW}{$%^IX zOg$a5RRMDOIG>`zp$}}?q%&3fN%hiBfbDMS7X?eevtJNx{0~Q8{FMQ#+aStYcI|of z{99t#LY|Xr)U=#}%YT#n9Q+yKdZRPIi(|;S@Je2J;`pm6w9Rb@Z@vDy3a0v-wlF3S01$vdIgIBy~OJ5Wg*Mc>k^K55kY; zxvwt%)b_BMWY-&ypPsBiwtuWI46I@#7!k?Kgigw4)?r(4>g~mevF1mIKG)~j0#i)y zxSB;qt*CHj@C3V@GWe@vGi{fE_Ru&}b%w7{aym0+t=ipPu%!0krb7RaS1gkn=goa@ zy2Fjr2lD}P_Y>mPElh+T6gYpV-Xt_`ewcs!X|yUa&*2NjZuGGmrgvH{i;HmS{bNZ_ z{_pS$Kc57YP_|_ID9f6k$xGUDrPv!;EBE9!^ViU+eRp5f`}EyDAkIgGRSs;lZH%L+ z#4PU$cZRIP4TZ>_0C z(s|XIlzHVr12!e&$y%vz^aj3Uz|dj65lT)vAs?tP{_O7dLO@wxOH zF-ZsHtCM>qn_#sY#$URpvwM5_Q6AW7f_n8{P!g9B3hQWlGcU{M`};?;!WY$fX`@ph z#s1VBdx00<SuM@oXg(i!wRa;-P7eEA_uAM#C)M7hr(mXq3x*noSIu$ORt&Iy zxhdND?YZK`@8>%1Zb;r(Bs>@mw^a*Ge5dzrZ%T(e?$&u7y%C?ayj`pb25|KzQ@=?B zvb}qE-z+&O0rj-y&~{Ddg=puXj6guG0-jrLtv0l3XRbcw(Ysr>pBjHH$l;a@KArtf zu!P2Gy>r=bV6ALjwV-#(6oYfl`C>-__G%?}nHmh!N!Or?2mpwI6#R6*s~@ubSb$-ZY5 zPTvCIaMz7p87HM04&Nu%?n1@Wm6L_jQx9XNZDhYqb=s1)zwAE?zF6Tj5mkI)JS@XL z^g~iFamm*C>43UnClBctX}_wrw)!9MjTuceWi|=A?pzygtDD)nxgY=QLuhsZcyP)- zc_487>W8r6LrULODEhqlasunVEA?Qf7r7K+j{8s;`rAq=Q_<(b-e*L3s}q`{ZvHLf z#>MQYhrOBjzLr8V(R?DzTK3x#_~r86=?7>^>-g|>ooSXvKlbgU#!&THSL(Rjp6lk+ zhpI28ciiboa*cj`I|2I^nCQd1!{CvP}8r(tM;~}ZGk#gfq&6nGyoHfrzL(|OnFZ%m9P!25mF5u-R z6(f>DwC|Kh*0MlbiKCsrCKO{P>qUtV1Kj1`pn3wSe3!FJ~W}31&Px@@WFM{c)G*+VjJRtJm zvk}VK+2KX?x}2Z8I~({t#fgc`MmsTi1R}aPKtBi!I%Vylr@BovRwOERf|xB9H>qYLl?js87=sjt7u@@8kt51N;k$I5DU zHzUOdHDX$N&vC?0?MIqtRuao(S=#45a^qplq3prJp&R$%cEG{fw?@yU!>E7_XX?Y! zecMA*D$C&<-z8S1-qX0;4DH(9e*5z9q9p{m$hc@|atr*2CFfHIhkFJsryNJs`eaH? z#G)uB%M3cY9~?)A353#LJwcS&tt}ZHU0veumC*|f9LsBKjlKeR_M3eCCh_*=FTA`` z&?T8Mxpotdi_J9y_S;1WS^ut(A*Csy(({KMO5_ky7Ii8h@^E_ckY##_I8F{ZoKcE6 z91Q0Bx}4s~ar^t-4sY={=-3WAbQ|x9jV8R!hc#c8*XI$$9}_mPc4U&rQoy++=G@0z%qa&*rAX!+SZEID^#Fv@F0)tFPjv97P@on>Z2wQ=WH5qfTTZtl?9;UV8Z*sD)W@AKn4y-mM{U>^w8H9y@kN$~FrCm~lK zPwo>1Pby%Q#W)~JWoM2-HW}Sq>wQk0fbi>8-C$O}JGrwO#1Hq3bk4Vb`AE*`_mIbR zs1-i8_36|pNE~}a5PW6W_ya~)a{&5+1GZhEv(OV`eiC9)Sn3)Vo-WC;p)3Z)HuaCW z9Y}XUAWEvt$I)i!3x7i_y2)S}A0~c`mzqiYToc{bXAp5o5FgEuSJnPJkI!JFBC4?P zI)z`sGqOISPbz13q^4*f*J{bYYs8eqIpOtvwJ|&%{8+2M`NDSy1Uf?T6cqt%nrz17GlrJ_QtTxNZ&wC^;SMt~DM``pQ5c91#zl^W!>O zpO%)ms!Kt2^du8vLcP88=?0_n1R@1;+)ZtxEs@OG0Rl-;HJ(l(XheVRCbIk(gkO2; zuGrt~yoPn1)yH8p7IUTWau%3OtMu2(&HZELsDB z>MGH>LXM40HkXKASHTKgn%NNGNq&O(((vOF1mbOOWYn;y3*(7sz5QGTJ5{(e;uiwW zqSN9?vVb*ubewt{RGFSpfXJ0^9E)Yn#W7R9)@}Iw?>?T54ubmtPfad=Z0Do_s|QD9qp4=oYlM(2FiW-5 zGM?9g=Pt5%jev#BwcDz&+MIfKs5S2w1A+X!7<3K$DsmlZ+sxBF({?ItL*Npp%Kfyb z)T#?6gU7)#VMHePh0>z1qOuJp5)*cL3zw5(vaikriaOUye_Y!$7E3xp69)sY3vnIz zr=|A;BnXZ2VG2rW&moYiJAo(Mj&Ul*vV0{s&8IVSr9jg>ArJ>}m@Q3*Jig0B!BsS( zd9?ey<5O}-Vi*iYG%{AEVa3T`;3G!FYoxT)OVU5~v#xcZiQnS8Lq&?>709jZ>R0*b zXQ-Dkt_M2s`vEQ~s5W}snVA!mstZ?iM;x7xjhRP@k0Ax+PaJr@Po%Mo)fOOeGciv(9rDH$U|Go3AaY=GrfxVD*O6KGvzsWtt^N)x& zkthk--ZuKQ#j_gLEx}4@_Gh<+4G0hd8C~E!vOjv^G(_oKnkV=*rO)t{CsN3|OFZYDwOwCy zJ4My6!_W^?d3k8G1E*NscLrh+1s5282d=#JH5`(Kr8`FXDYY%EwOz5B#C0(K;v@vJ z#!<9-{ZbwVV=T(fuBH*q=V97OM?f31S$24LOmfmtL1$5lP}}d}_&nGOfx-M3jk6j@ z;*J1e{ifG#eyB-eZzp73c({P5LfeGu1J$SwL+4KFaM=lnai522nd6eOi}Gj%I9_wX zR(+!~+MwJmU7D(r?WZ!*NiuIJK_-Z?d#(MveHDf1e-N`DHotph?79cj&|C1TN&74) z7ZkUgXbn{YQrD_SRZrk}Ni3H~I1*RkTC#*~tL;JMgi2G7Ig#@oSt8DKD2 z;T9|Ai_l-DRVV~%q&p`1zvjllJ}&9xLO^+sW~94Lb@8ekRSUKhk-%aV*lG2RQDyT3 z_eqHN67?y@xi(%jvs0gVuVShY(*e2}`i^{Sw@jYLTW0?@#Se(fLyc{8V8te^ga0&} zQbKtN;JJBxInTTa?^q&iv`SrYxd2=Zo=2i%m%z!&cUAGb(c&`+`kRKFT&%+j*@m3d z36kI&T+&$jw4;|>cy?$_QMb4t<@ibH;}6X*{6xUIx8#m15og&Gfqv&rFGB zc6)wTj}5k;(!WzLd6Mw+hb%+RBFnaL+MNvZPK?WnUSYH9?36hp@S}zq%m6Q!O zcEJxfS>w)R-LeX&op$JX0nkM#<&r9QK@X}ZoC`)FtOD6UyJ`218=X@UM#8!zXXZF% z8LAs99G^UAj3=sv;i`;o1Y*X%TKd*}Y7^g1> zh2O}RM#{l0)D#&6bj8vNUzUhtDsUKuJ@}lUZ5o%FE9n`V@i0C6qOHj@@y;LA+dsU| z-9~6cL5~j9hBEfxS?U!UQ`U%vt~z81W#LakjES34Gw-aqJWQW>3n@4m8f~v`h5!vk zk~x{P!RlI3g*o7FotGpS21I&@m%(dq7LB6J9Fl@zwX{n_P+Vgqo6q(V3Q{j+kwtGqD;69PpgP|?AC%I7Kbu6ylib^oWPR1@&16{ zx+_>az-@bh%u=vZzS?5dM}7~>m|B|#b7DDZJQ}jHMn;chK+9|cAI7F?srN=xryU$; zA&-<)^L~DlPdnxXEo{ z>9ieMN4)cP#?k8v_I+tn6)11!h}D^4vTgV&uUy=jh*d38^Vu{kxcsaU8Xaw1h+>%Z z6l%|9GSGH@ln53Cmn6!#rZoUafwA#rxTm*WXg;@9feO%0I<8;rmSbc76NSc?Tm1w8 zNQ0Ju`g;9SoF1EMfB6nZ(sP}J#8V!h+!9BlU|V9+=||VJmNrppu^lGj76qtX+rpk% z-#r*li-bH4(6Gj$UE+d9MzfnWr~=)3_fXV&DTPzlO3oyOtfcS5v7I5lD#^6_l9CJt zNQVre1id4%RVLj|UUb;5(3%ZA65^oJfOrTK!4d%1&SuagzD}u3(Tw6_o!YdvO0cG^ zPDmY*?5fJhd{mj^H6E>KKKnjOK5dtFq8M#UoVtQ=!5)auow+`jFN#*h%VuUvHOBtf z@$084%lTx|s?`0gjZ(_}tR5E=T0@x-HyP(@HiU_$z9sgYg+&PCOrLm-WZd%FyMI(#bK3ZRKOpy>MX|12MGXd2B(OC zBBSAHyGa#}H<{unzxK==Z{Sn^r4>k4XH7~+u&+RyZ2f9HICAR?D!FW`BqtKzV1ji% z;_{P#NO9f{`WGAsPio0~xb7;AY!G$eZa5QpW@T(Org!8Tk90x&X&9GMhP}Ulbsf0G zwrw%Qnywg4+6Zf1*?U4so|-HI^&ablo~k3I9j=xkMWDDdZj`H?KLA4o8;P9)TIB_Y z*T{RstP~P&oaN@R>DwnmS|)q}U;1qTqc6`=aR6m*VO%y&v+7p^4VNKhMUgq5hC7?A z&lZ#(DXJ+`1;RakLn~RGk>A-~qG!z234b(JdRaTUX4mcfHxC9bnik1`^u-kT%JB!iRGABP{ z!ok&!(F&%2Bi4B4(YjUGMa`+ZuYG9@ z7Qph=zang`q9Rsttok_JqF)u_0R=}g%o(@&F z$WS$c&7N>0-1jZXr|~3N%paa~L~7gEN@6>Ld^_7nc3d#)mTU$ERlPe#MmW|#3T_~e zwz8ekd^%5$d>DQsL1B~jnPyEcee{DQmJ|b2TP$)aQrL8;+JIwQIH^dt`#O!5tTN#} zXnZyjzC!*Nhsy>Y*?gx=1L*uTMFPayg_8hD@^7|9^C6=|F6I1kAoP#E$VUYSRMPls z-O%!HnpYB6Qxs9*c)ccGMy%?I402rFW_ZgsJjf^)YuT4&awz40{ChJze^&)I{Ep>+ z#P8?DDCTMtc}>-#1z9JFgcyc2shOy(O6h0-NF#yy3TlX07NCIAJpY5$^5glUABr4U zUNbJ%MAsC_!mKt0cxL7jNP?9?()u)U1$gHp+zjs}XbzhyD`2ojMi+prkZ5ror?E8- z+5+~DN+vKTcZ4#-bLFkoqe}x>Qjq<5IloMYWt@_cHe@f_Jak=ehUZLGUv#=9=Y+Ki zLSwdNK4kct(AjoZ{iJ+~^|C378vldVPIG_)=8>MQ)rCM(=s5MOOP=8jX{LxU&xSG} z*;=LVBPN2N`T<}6Pnv)|NGCO%jabdWMI9;qGXJ~`$u}Ov<`fjTZ+Pc$e`Ome7B;tS zyGMzzRhu^2LC^IL+Rl9_mJEnqZc@AC$y~6yB0Of?PYqx*fhNul{+5`=fyS=&wLuz; znGbn1?Dd{%kpQ>QjxKZjyl^>>t$I%yOwO|eG-4ey?r8s6&1xx#A$;N*Uej=Ax#1kZ2J3EeEZc%?rp@XL7uX=#9qGR?BQVqLfPFRu#b;E0_K)h0hlUNldJdL5m3bHE|kyW502 z^%2RuDi<3X0~iJg{np{yTyDhR-9YXA2uctzWy2I&j$EXwVXBCU<}7GxUcs^5A*d2N zv(is@qd{#&MqoCS0ZRL5!3OdWui6ZcOfcHr=+%vsAu*+|*obrnNcB5FSjOpoij#Kg z0_}~ad6pck1A+L~wKe{mrbj0^3W>Iz=nL^yq~!*cD}b#?+@^t71V(F+A5d-iOLkr0 zD@{_r#Wnz97#S@%rtre+-rZ=KXaeg^Zg|Fb2wDwL8b7ib;^K_dFJF$WT!5(A^2rnW?rZo{BNRnk=wDy+x zf9FM-nBmDfH6it*b#oNHBAWTO6HjqH*<<_vH$n#ISqSpIoJzFbjSz$a8~2Zz`*BKi z25b2}!$XHa5)ciSXw9pZ^!&$p3b-w2ka*ia2L)|j79I2%oIV_Uh2NT2PUdUDrjHil zj_HuuUjq4}_p+*xZqW;S6LVtiN0h+I_sP-)>B7@APT(GRqS^$wR?K4Y;3S|H<7E7^ z|I)``r0@_xb+%CC$8Cx}-7FA*WD3m6w*ku;*AxlAxLA|Od}W?Z$U6Cl2RJz31P(yK zE`bHWAhz`xXg=j!yCx6-T13Wtl(7V8uB;Q!uJq35w{a;s)7TC78*N#JHah6&=%VQy z-X6Fwsg|7R(Tto5MS2P3AY8T)*AQpv*!U4|#O*MA0HSiO;^vkiji$Q6dSwSc2xaZE#m{8%aMr~TcCt%P(`!>Y;Wo(TN-!;*9RVb zs7v`XH4)$|G>ldSdKejj28L`Sr)X)EK2z(FU|NG6TAI=Vj*8!(mTmyq9T2f;i z)_^}=uLm~*NN`eAuAOK>TvrHO1;9MbZ;A6bC}S$PM$<+QhCEgWF6RShv+x06$-9A8 zej}iTcDWw4RWXpSDNU$~15 zeoosVpjGjL)>O1cpA0uo+?Y^HKUtC~P}K`7nlAYfg8|fuSH*3a(*dZFfuU%x5oHnR zDm-22k3*|#sEjFfwPmPwZLv`@puE(^wR&kp31DAwzX6Y8dda=LX-V_Dy2)W&RreK> zW@~*{Ed0iRx&=NfH~eCAuF@kwRuGnIKw|?#>rvn*UBE9V5={{48(DcYO`^e3Oyk9> ztZv8nrs2G<(A%p2EV^`3GW1On@~ z86FYsOhKgOVcIB{_?1#hQz#gkRqQ;vQx9AXccvq>(2t7pwFa%Xty`GJq0?$WRa0M2 z0J)Cu2}XCh|F^F)z^%u6i`|P@1?-y9VDlag1c9(CPzL(BF}A;=us2yUA0tBHf06~P zto(@wjyGB+aWo8^FfOrw0U8KaIT}?G)@vXDZKGQ}JM+5QN(C|3PU~UW&ph(@go$2< zmg5p2U$a64TdwEA<7G8WhbBCQXaEb4l9mF}?qSgp{5Hyw<Xeau>+lp$go`dNh>N*Gg%l7=ps?iw>`(!VbTgZx4}jLt$p7Y*n%N5 zC#;Cli`Qs~B~5&44^pwROZiJR;LJ9Qw3EOgAXvEhlYF#tff;6ygo1U6&w${H6lk~) ztjCE&;Hn@qj~v4;id;8v`efx|JA>sOq;${$-3baFds_rboNGjvAR2)O!hOD;F^Nm5 z>)Iv~RMyXQQthgdkq@VdXy(#LE>k>`J_no=ZCv~TqE}lCiex@sy-VXKABwIYO5gOC zca;0nk^t8!$qWOg6gn1FG?5wi>Yb~Bnp$!PfW4&l;N5p7hcwsEImOa^fkt;G$)2Vh zp!IW_w5fqW>~SGz7F~Gn$@d`b4e8CphD8PZkxq|RO|Imv?LA9XbG`>opk&`4-84z5 z6|kr;eaiw=H?Xmp;gEj*UydLUXjOLvZWJ)rM-Ou%=0Qi}iUamo>r+3MPJhiy zN8a-52;mNH%B!~RplOf6za9cuv#pc9gH*9!eg+Kwwz-zm@Z3o8AWoIG*_Mp_8LZ?) z`$`#8^={eH4VFMF+RmiYJUO;vuqD0%5}xZSI2H+i{!1Xv^5lok$RA~7SHr!$RKEHc z8C4qux4Wu<6ztN)^mhUdAip|tsu8{2IPM(L>zi(pJj9GKuwuY^H9tioA-BbNHeQvU zpxi>lvi9e-(a*6XPW?d^02HQ^J3#QnO9|qcy>0{g8|uOxUvOkhgOI=~FseS{Ajl9l zQjx%X1%IY|;r|f%$2;a0Y`K9hVaH z05K2z%6u|bGzto0RGQ^tx*X>W?&>zFM z#GvZ}&zaj!Z5*SrmFF`DY*lOyRyZmK94PKK#0cqT-szLk^A)9el!HY}0NL*zk>+$D z$~W(UmTNf`S%4Lt9Jdp?RPcOK0IL51=mZA=lTS*(WaDp}1G57{lEwG+*uW?Q@pEwl zc!IPNC0&Hn2l02Z( z;Noj=z-*2w)U7QtNb89`lG1u*QUm0g_`iTGZ4ZgG;8jLIi1gT|D>Ru~aJ~>Uf|8=5 zB|z?0nFQ=gjh~_0d#%G1?MW{o^>SnB`2zvb)57mv_suFLvEs00px)oVtw<;|E5DY zrC(;bF-ay`M8C?SKdM~}CcNgsmA6*`B4tPkMtKF_y89?mFVPw_^KX10DFaCks!A@w zWM6VH7hvVXtQ#NifwR0cqS^H)^!TdE%>#kVeYN3(D8U>qY+BQLD6n}OR&;&<%%KZ0 zq{TH`eruMo0EC)*rs2Y>dZ57D(N)q3W7Hoz`?bCv0!CRkG*!i*j-wcDTbf3Kp!peX z&>EZ9E@=VDCgBND`b|D&!9=0Zw$-J`m{0e%q0#Is7iH5SKq@L(tN*$B7XgG9s(L^j zVCfcWdN^fLL#lp(o({?Q!JgX?En+tIIL}u7;u|)$AflMR< zxtg(&B}`k?^|#%{xL^|)NK0CWn?fQlSwt(tVp+B-hLUJr_8k>aJ%Yfljier=oD84jINk-8|9 zjErUJ66b`!6b2(RkRDl?d0mySHAPESfdv(g8E^Oj^YhA+oDDQ#o(AR?P}>b_vov59 z;4!H{tn5tyRNjbyK)zn)wvcxo3w_I+yK&6zbxokIq$j5m7_stNY$*V z?kQ*sCuP{ntY)%)sN|b`iYfxwJP}7m|52uV;UotbFw*XOMhpKPM;m;Je1n^;uAYy9 zd2Db1EM#yUd3^EDBYit*L2GsUEV9lk#fLO51bKNf=o(NWbPCpw9^bbn);(ovq8|VC zM4}Nw_%p^Z>FvxlgMCl39{0YB%K&K`aL+)R0VXj(3JONQ00XBdDB$X?K_m*o0{DV1 z47ysDw%|;pHP_zCaga7?sNI6avVwsAmKbm~T0p^m<(}LJA|4!(p)Hs;QSdwg4aT5u z2&;5>>*L5^dImUC^zD?7Yreq2>INfRZsu?TP0hnH1da|OTVWf$RC7%GZ8(m0VBd5; z27Adh>Ao`_5J!`I0)XFh!$IZIE9?JvLibj`@ukxyA;49Gp$vq^AQY&Gy-5&i%(^Yi z3ScRpFdYwr=Z4`lgL&aN`=GSs+-(E|;vxL7J1$w+<+#eF8(=IV1qg|! z<&UeS-_RzF5}2{TQJt6uymWLGcNUa(DZ~%R7ew;1E}qD%B9T% z0p|f?VzbP7cx>}8zw2W9orf~vx ziDpxbVsgOV6K|>z?HG;>>_~zHo;Hi%n;!|y*?ml~z#u$20y2;KY$^|gTsqIb$+!qM zF__Qg5zOj-mj8bdZNU-7V=$kV9&ZAAL^M9WCOhH0#>Kr>7HG%}3?q2H#v<@)J*}d4 z2wX}U)-A#Tz#Gh?+U_1f{G^;LH+OC%Pc0bVnQf78?&n2*&k$xG)BA8d%bw|#;o3#$ zf7&@>%uc<7JRXqdnUiYfoDU*ant66!mDR&E&0GVsG$JHLFb@2rqG1h07$B(2z*DD9 zXYn_U+O*MOk5S*D+8~Q8Kl3gq^+W$q&B9F({O0ksPg7RB4zH7ll1=}c1&EHd_Z|ls z6XGI}WbU;40KJOTphB_0sChgNHlYQaQ9QtRTtAvNXmGZ_*qmXl^`jr8LP&ZAY*Waf zfCZDX8d>r=@awSeD>IJd6&Nqb@B~|W`x!dL{>AmW_zv|uv~K9l-3;b}jEojpuC&wK znkcT^jVZx7Dp?iSlqb%sl2)NFWB8OHkpeGCCkPhdGz{22zOYhn&Ci3@YFTPf$=zU` z`rBwGDvufkMhk@mW$j?j9>|w3)67*r7z__OZ8BD)tG+PFGGLoxGFX-_Y#P!mV-VA}fmA&j z&O&&{yvYby1hz?aG-I*a2y?|o{}QbPCynG4UW#FUG0CpvvuwvQbmLVq1~Dr`Sl9>__60q zFF0mSv>k5-Y@yu1KUa*-H;4It^TraJTWroeR@JhG*5f_avd}~23J%Ch7 zHP=T1M;fdAqiV`o?+utM1rq*fLMi}ENOgd@*i{Exw`Gf?geiB>I4QO(;$dv*=aAa z^LPF0HEr+{Xl&D=6!ZImpvdAT26M-${lNc*pyjoh(`YssZ-mWEB;)5;9x!V6NxK@z zzBeW?pz;^$*8ZqWKfp?XKP}uc113jjaM4FuoogRp9iY~~@6-dgxJP>9)$Y5PZeYil ziKGcMGC*#c1kHEIch36&fJQRV5{!pQ%fqycY%vCd z85`31Az%DS+x8FSFVJxgf(bbTWUwyFF(oUeQcHX;H<*I10f8n8R6a)Udn4NH|0T+8 zHZ6dX0GHSBvYp9U;8g)00KzEtUJdRqmj0IGz>=Gga-)FI({Dv98fp)6_aJbgXl~OX zg}0k2+>QGzOE_H?I~1UNh?{pRNd9{Z0v^W{j%djo2iC7ue&|-w88EL#BYpXHcnrJ>Qd;qjK;ON7XGEwo#f>AtD z6YjPKYLQSde<}oqeDK~Q(82k{Qc(U91C1^ojZF&+cGOj`Mv%o2iw_oyr)Opa>s}xG zDwOUUytFHRL0w&)G}BI-b^rbQ_cV!!pK#iXC7h0To=a@~HUdcgXs} zT;|k`!_G$ECw6ro062m!f(L9TtK;V;m>UKEKyhAv5D4tq2yFM$)6WM7etGZLJ}m8C zy_O|XGqEf0xNF>R^iGvkWeA6{`>+svwL^-%(^~Y}TDz%v3qgqWL+I{G*iysNwEMsv z!-(O>55%|{=P1u~(?V7GJRaQ{Dsvr6ANP59=T5!JH!P+(si(+6arar8*e)hq)ksZ} z={rnYX8f$RDc)_WPjjgL;MoIHCRMHo)$^^RlsT&bHKT#j`m!;v!oKfbrH^H8_dBuC z7}4yt5&1_RdR$7Oi0GJy-GqiA&g=kJ~Exg)!ad%Fp!DrW05q_OW zBJPn~oI9KM%9+|kG7*$3{(ISB#SLg)^YO_r4&5x=b+f_k2bfJ zFMFkVQhD!O?Rges}2Vql7!61!d6C@p6@TlTrpGJ6KnAIXOmmK8ELLG z5i!u@kKP<#8dkFVFfkFfx3l&waI{u0&7vsleN+KafSEhnCd|FUoN?ny0) zJhkub;&4sGImo2*;P=AN&TwFQpDrbDb&zouul1SgiExTY!1^rBRGMa58#VwMjkqEGY0kiYiU z1s0Z4V-Vnr8OXz5{AMdzYLgtLV-sQYJFDNuGj0U0E`Q5FdJcI}0UD4-f(56kNE{oS3_t<#>%kpi1)$D7jkW$IFVq8K=9EtiKgnifs4PLCL+}Yvv3W6XA(h=!RKtM!# zlRoqs5D<`(;E41ly@T`)5+HO?>AlwgQF@O+LJNVrqch+7-@ESp?!9N7v)0)wixu9y z$-DP{`tN!6-jSk?b4`?yj!vD^()Ev!9v+Lseqt3hC5vaRfxGQ<5*d?C9gCgYVl@kA z+uH@jOiUqcA&&;A3|wBc^78i3^q(V4ggV7@!02!lJh3FLye0O(Y@$y+hZMM}@aVdFYLM&yW#; zkqn&~aB!m|7Z^BOv88yeFNfnc_aaoO)eY)IjoMus_B+BYdOLe~+|~w*igt{_GAq;5 zz2USeR8cloW?EJAIx!bn_q;Hov@~tXD4i?pPa|q4Cm$VQ^sz>g@vu?pu!I>Qu5I+*3w9 z9aW&Pym|R@;O<FDS>Obt3qQ8f!4 z@lNLOy%ud?OYb?+1klX8R~w<)hKJQllDSnhEX`PYq zQy(MegOT;{ISQ6=hhO@le6smq){N{L1+XuhL7B6(LkN|P&oX-O5`4+HC zkCTz%Og#l(ZRhMoUSo~6q5ZZh zcGf)f^Qcg{mJm!cjD8TJQ{jzw7jLeiz3$h^s!I$|Y{9ggok=&&NCguzBXku|71iGN zcSwPj@sc_z3pHJ1%7S2Ij5>X)oZq~nz<1^kZ!xs@)4I`NFrDiBZ4+5Rt%7DA9;ev5 zljZBsg&%9Y#td}r&MjecDc%*;FFPJZEH+s4WIN%fPx%o;2l-Pw50;Sj)S>6c2k0 z%eV2;NR-(VoL|2p!z-{lYy7!uch2ib1sm%vtu^9V%%L;0#^`WDXN+WFbPU^I0b*0o zDy!S+f)ypG=+sM4chBF&u7|Fv;HPF#5v4PEb8e|7Gb_Sp(^B5Ic&LOHBX_tLjopSKNq#dl049=Sg z=E1}cm*}Wd_rBC(A6NaE-9qHw&Jqy;f^uU4R}|SS98MhwJ>5-+To}#{S~(I|irAf6u|W{1YSIoacN+~UsC zcjzRDHB?lQx%78NF2314xpxqWx9MGc<63ps!x1CbC=#Yy9s#U)_+<~rws5FOT}1uL zpc1?66aP5RKfXQqv<;~faXKMOv zP^X7en_pQtYk5T0eA8`{`MFT8-|EtDuAk5pv2SDsW12nh;A4rdWS{=Q2EAfV0~}DMjiRtjOxAV)SUF1t3{YBR*><)R?F%O2Cm}Q^HZzhv zJ*O_)_yl+ml7T6pW>L;fF#dHKo_Ek?R1 zWJZK;iS1hmv9O%j-f~zGp?hNczrS&u7`Nzyj41jLB*6ng{0dg)Wr0PKoV{!z3zg>{ zL=+)oh?f+E9e_~0^=00=&l*vmIe-DJk(2xGN&LoV&(>E5M7jlq^0f0%g-)SRq4j5{ zHH{#s`pgP)M2(*N4}iOa#$!UWf{MZl0whD44?hy0^-V&SRJ~0tewbRjY7TF2Bd6YW zaNrJB)GBCeXAo?~fD7@1{AcB6FsNb;3d&^5Dk~~T(WY=}4n6A+4WePX*7YkTiZd`4d~*zPoiS8Qbgnr z%u`ShAZrMFk4q5T{&s#o?CCMVwjqmc9>3~p4Q8;c;9C%*890t=Yp#iQ`0Toq)X<;A z?l)>u4D0p^Z-vrCn6RF=5YvOFpWofjnw<|XZScs(f^~bq5*0EqMVN?3(wt=ATJi;C zNNPtyvLiD$#V->-?E(%Bm^wE2yl(HW&isEM+y5{6o<0uAdUL3XKBNZ~kRZP;qnDnh zNE`6o8iye!THs6|E}e7()$4!jPUe{sZ#h!?nIj)Qg#D_TYn#?b4gNhYLvj>cqEkGD zMn?t(fs+@eW@h%(i1&ZH5N1*i4wML4TwE+DVt1TxJgyXl5+@GM1eTxz`%BtNrmfx1 zODdI8^Y-UAG;dE1f&A{c9c5r(AXsn-jLD&Ob+gV%;cwsa`AJ(Fe2KTcjpQc65^9NB7VQ}zOjVhWatfcjF%C1N)vWsD{(z#%ID9qd7z>OmI( z&EIBp0qGF;!miEva)+E}G>L^qaW-I1&l;2*Zr5pB=~$IE>0;&_1g8y?Qv$LcMl9WA z`SXwD+ZS#*OuaQBJ!=2qXL7OS_{(62IE~=rx8J|0CG*K~$%c$oF+28K33*#Ojn7r< z>geo5Rm}B6^jH_>X%FR}T4{4f9TT2#>2Tk?y&LHYb`cq<3w6thB>kP(PZE+Hf3^?` zxhQa~=-62716Ec`y?AgQvWC3_kqnf{SbK})^IA{=^ly9h`CrB- zUb#W@FCoD{pMN7(J^b5*|N57*#4DG>{#AY8pKou8n(E(1$NR4?1Xtd|ZplT7503Wq zgnZ>4TUf{vAB<75`S(_mw*+ub%QgRZR#sNbir24Sj~4#VC%z&+@zrN==EzUsAt8Bk z1H}LBcZeE=gzght$d!L)f%pB9zCMMVf*my6oA{L{UwO5P$2GEtKWx@J%>Uv?lG{FL z-G(_GngE3p7y|V7v*ar}g|ZYncdlNI%4sc{00h)Pox-^goW@IR_uA=B9Z~LPggykP zNQA4!#MsN*7fH6_g7`a;s>4n-sF~T>SPVWmyzaG65cRL`eBi<~ySJOElarIPQ(VhF zr$0{ojl}!Ca)aZ&lk|Gk)L(bK{jxVupp@~q5CRh!Nkj5U;lC*GmT~(1uX~7pg+nV*7Tbl2Zu@?L{gq(g_lY*Qr7w2P#9J z{QQ)JMBycc9D=iWza=oOUEvRssRlki(Gs5j;(%{7pE&KA1-F=qU-f1+GymsjNdnBt z{~-|ZA%FcpGs*vJm;dR=Tf$AbsIR=StDeD_|I#ktv#l7m5O9KME+~L!X&(HK;eRsW zRC3JxSP|UaR`ajkCjQoe(l-vndZzR7gj?wUveMxC6ptyJ6HJa4(;R<}B7h6tA7FgB3$_n4T1T-O}h<(aGMVRQVuLrhhg% zd!pP#u(Zq#EtIm%%^WW5?XgjcR8y8Het+s32snB?X;0l-jsQMssolAgb%KLA-7ac zkTGg-*E>JjFsNVZ+ngPZTrbpIWPk2LhaVUXw5vwh;WL>OBNhv^IE%>8BBZj_5~^^E z!f*A6>?g`RYHS8&ldd5Ql8~g>IefMJ_ROYMN7gfQM`aaebMoKjo)krqx z7555^6P`I1=J@+xlEAH9@H#!yi}ORq^O%g8oc~}w8BWo4bFD7IoUi5UH^0`0q+Y?D zl+TZ-^30Frp@tyvBh5>+svG|K^b@kK=62%~uXh(Yy!IE|j7;XDsr8CfUaWt=jG5$* zOdT#<51~_>pQtw`jN?yixW>MIt(sjalB`8C7K@kGnHlNU$VeO)u3{JNSF*PY;oosJ zo$YO&v@h4wdv2)1zIVIc;dzx}@Qa4u?h&UE06CcNtuQoD!s+g9MG4wJw z=bgF7;M4t0FMPEw76bp0Y~0dV*2UfB%;jmUl&L-8&ze5bazZFy4_)mkD(Biv^Nk4Yu$Ts266kKMw1gK@2aNo6!jHb2JuHeq_88&ct`ABh}jAR3QFI>LVr0;2<5N>BX zz+xJa^(>vC;1Qv@`5=xOD`w&&0~ri|IAu8AD+Sl{J)Q_z85}62E7{z$D>&wdY-E1@ z6LvVhd2%W*7nx2-9SEZq#bh@57@_g=hd2f)XDm;r>c(;B;4savfxi7I%ij_a7JBhA z=+T*;qO$p9wf3lYz=BN=Ek{ZYNj29L9alm>+_c5seZS$VtbITwfnK-@{EyiPKqY zTmz3}CjPWeG%|PG7Ll-M*>`}{Eql(1o`?F~wA-Clb51jpK>RCI65Z`<{ z^^hwTB`RgL+2LZ;pL7|^bJmL<5|Sc(Sn0?)MEe+>51O21!>f%agy8#1Cwq(5j~(&# zr}L`1^ zTk$^mK|8p%^isNAOe|(n^7v`FiT-fgSAMUBOwD9&=lFkY)vKYO%0V@LX$qOV*?Y3g z184MJ&bo%A_~Y-5lufTgut4HlUU@lT;QGmo`Ss-5%Ee_ol4?La2Q5ZOH9p<5#?@U` zDPVi(R+uUnO2E zC2ibQRU%74MY#y+BUj#d5CMnR<*qjGs$$WEFS>5X1-95+9`TBM`R)eicoUN`sm9$3 z$-~0SxT?h>8-Ke${$3f7{3vzghaRp;mtavCnc!05kvtAL!_-Jla4^h|@aGpLKNO1= z#B~@@yJZXH4T|Gx)5XQ^Be(wH0Y73+=Gzpa^jUwY8|=rIK)bS7OQjH|?n8<3nwdKp zX`16vjy$F7FWhwECRfX=fp5 zb9J<0O%BHjE{~Mt%2%@Rgi)}mWe=+vn6t}61q{+p?`eF)+f_*@j!bM6ahsT^mvZa% zb2aUSPU7soaeOF!{&37}t!Nux@8zi&TC6M~$mnlcuy<5T?|TZDAPgyrc+4BvZd5g6 zx6DsMC*fHMCg)FD2!;Hj>hv+bi$%t8d~|9|K6cuAXL5S|_dow}!h|pWB6HNzr4ei) z9y{1VP$m>p4;EV}TswVMYGtHb4kU}`{JHObQ_D!;OzY0M9Woa@?5RhipvaRSL|8|3LuWw!Q^^@Mk{Chaoc4{vj(=z%atB zMXd`JM>Hc%hN$Vqa>rB7^PBhgb+ID}lDVC#;r7b}A*}D|y2%=by9U=*sk+&l(PWaJ z&jH8+JN@o`a)|adfRkTPg35#fAKbo9)&Eo4GBGIl7WB$8_o0HgGjkL(%+&Jd&O*1F1CG zw|_AmN#I4`M!z-ZA-#VoYAI(xG)1`SV<1DS4!%F7-lvJXye?M=?WO5^{so%m{hjuN z;cU}sy%?f0?-|Y2B!Vo&v|y3(GTqNJw5_2TTnV1@X)KBnvodn#?T8{vgGi~}_we&g z2o5&4U9E;PfJZU!W4QAl7Y_QIT%9{?gD{I3C2zPHiAu1sX%8+Clo}Q~0O3R>K9K!XOFQcMTQq#wC{RW|4 zI2`2lvAc4VeK%rzn>CVIEF_0bYpPCbJpUifU)*VXjs z_xrCGV<6ZOp7{yd1l_SPX4Hl+R0-vd{gF+LT~^3<+aI}nQrtqQGu9);O~pVqzpg9B z75wAYzLoXkC%Vh=EZz2kRkgJR5N=8>L@sX##ieFJ-2_}{MspTJQ*~Y?M5=g|`-Odp z#u#=i=ec?gM~2~OyOPjjH>(%LHI5s)PK~)O-cEAxwSv0l5)L6M-0W>h z2;=)&nfifITGDIFhO$()k&T`r$wn6?)wH4_!}K9dRq>C3#!UsfzGq5=K>R8el_8lQ z{I1H2U{3J$B}BuKT4PQ=`8n?;Q*@XdaS^L!pj#w$*tH z)1A0L^jT5!oAWBVnu7dvFMX3YYazzRxXlwG-})@PRdI;^pL)3=+~W9Dt63rJoY4Ga zhA-wayPU~L!cNABEHzb5OG_r^^w?yxCr}k=G~BzD)fL>2)7W`WFpd`VF^5shnJr-= zbZ~8bRjSn2(^c{OK&mAlf^xrdx7JlMdo^KINHl)yaYz&`X&Vb0S7iJgIo08kk3v4|FER)O-@N0v6xnGFrM7= zQm)qdXjYdsO-`Q7Nev`1+jw%OBVOG&0Z|~4VHgK@+$F@*=3R`jzF)`9UBGX zYZpwytu#55gs_B`Qw~B3gV888{O}M9k_P);ukv2}V|_^I9?b%P;qCng*Tm;ej_woI zs4;6mO4kyc;3b->aN`z&|8-FbJ+sz-a1Y`4M052mDEO;dHIA|g|J@SSI5GlLl`3~4 zOeA3aFI#IlPa}Tey(Bm8>+Ap)^6xdL*ZOwB#J~c;y)u5{t99e zCbpf>E7<#b|(_Eecn~h3$gVC>L&R%H~C6Ls%9; z=Q(@L=IKHe0mfDFlKH{y#Uc1AikEcU=J669o?l9jtbLa4!CRk{AKSYemC_mY^MP|Icg0S-Qi(K6T- zS1sE_e2Ti6;8NH3&bA0bdF>L_Wpf{N0`rZ>J!?`(Xz@$VTOYIxzy`j^TZ^9QS!^3i zR1P(iF;2JrqFot-l^fo?5FgYeyT~5*9Gj77Rrzqzt?<}&qn1FIg7(HpH0=+F5q&z- zMzc7PE}K|8gGxPXwzjS+xko^d4ihc)?$FYX!Vc&1!6t=J2Zt@a zn`RN*mKqac>X)2v3v#c7(LC6l3x8o2mEqc5(;fUtMD5+BQ7E18NK4au)2@ZTIMH6| zonIc`hPI#bn5!SqJT+kl-1I*15Dt+Nd$971 z_w_V#?jdp*6}YA_=l*p?>HO%U&;u;P0$*2wv5u`&2Ll#KK65Q#TXt!7Ub5}M3-_|z zfXxh7=T`zs6msCF(t2eXkVw0Qza0A?J%@E8I4?1y?s4QuWsH@$ z5oO|qCtFl?XLy8@>Z&1Z2;ErQGO64;^dWqr?=#=1Q5Sz^7K<0pmLMUyZ+P$3V@r4O z#1G4z{!i58WGaMDmt@cJLT0*;NcW&Ei9;$heqG=! zpjlR6bi*9^Y|BQKZ;o@ZiJ0+%$6FnE$_wv0XdKZ>)5Pc`1KkBqCw*~@wz0b9%>cp^cFL>)XbJa6Ux{xo3V+>oa zwJAs99x&^alQEXA9P zRMrJ5-^}u$4-yDvt)kwDOItCRxqbueBM18YBL{%NJIiD|4m-03!B?MQa>Bf4EDsrX zzQ?x_T=rNoD{z@LD1RHvZ3va8*CpvE{n5iZ!o8UuhJw~A!;uI)ne%$7UIEnGp2}=Q zOo17F(9yOp{(IDD;7~*SXFBH$JR49{f4vT64bG0jxBv0H>L!)<+qqSWh-X%GcLdSV z*51xiWoL{0V8{i~K%gubXRaN`BV`OJ z7A)+lk;O5(%9BEK#UPIkrI;UdpJ}qkU3n_+&1Y>nVqDK>+T3_9EJQ={_9l0F-x6te zH~S?^rxzdQ0&6?voD3ML2&n5_Jgs5UVX{qxz{DZn0w)h1Qdw^0_)*_3u4&knF{IzZ z*Dp5}oVXY_<3>*)z5|XmD8S~w(B02L)N!*?`Ms%sjyl#{mG7_^-xn98*SLfTh9HxC zzP?k97LiG*)Q%x^R*^46Z^`bSzJoSnT+drmll_s=eH_i0UL>?*B}`I_J0VypY_ong zh9eu|eBQcMktCvqp&4@!)GpPzDj%}yd0*tlbjT9hR$Yl1+rtl~yhs?euajRH!ffE% z-KuWdmbAB?14q(`^%LPU3D@#tc#Er+UVN@b;h5_R$4|~UY6Hrj>Wjwi6S(x11-=4E zMS-;Uv~mNZWcN$5$oVr_I3xN7N+(E>hudQ+G&#e|lJ%GhOv(iX`8r6_B#qmdhYU0g zdFM`LjnEF0qB`?9lY&q-VnRC_X6onr9XgPG9M(%K28bh5YnwAw+`F`OsNV9#YqHYx71%@LJH5ANsnlhN)#Vmh7a zj+=SVhhm3yAJ1O~dlyH0G#m>`%4eejg@+1iN-s)(l*xR;Yv#!^uhYfR1PkIzPPR;x zv~VGXu_ZZ8f7}SkdX}pZoM_S3-j@V%f>$u(Rk$cmP~`?AVftRRLu2pF-QZjyOr^)j ziz7 zSJ!9jT!}NYC_FPWGlJWkbUVS?YO_-U^bzcMypbI#DXMd5Y~68{ZmL*{&Uhwg*xz_imH#LE-(scdVE$`f=ZA?kUp?QgA902%Q<@ zY&woVhz?UEyLd56^-qrip)F2>YcUCzx!JV3kxNq^aLmAY?AEhOmk^wVT4gpaE*jzT zvY4jB^p4I>%7Dzgyu8<-V{yHfz|$x#FSqycY24q}DP}<*j@wle4f*b_Gi9jUT%)HZ z_+r_n9Tcie&11af(32+W_8izKaLLoN&UIyOb~e>;a(uj4S1jc%m;$h~=mZv9MMXuW zRj5@}UtdHknK|w(v+eEU)J!cWP^XGAM`R?xSz$6%>nOPRURLG_N1PuKkCoEX+5q+v<0$L?87WZg!^|FZN)X~S9rVk#r_x;*1wwLXwIvp#gDYKXk$x;j1n{j1UdVV^2oX%1`!!=jyEStb%0`ijj zFJBJ%U#EU7AyH~oS=in#SB-)K4pbajS;@1jPM+CD0@rV|J~<^tv(9h=T%6fVrLAFe7k6!=FqH93O=|8@0e zNb(q`b%mxyvSVO*@8;uahXZ#U;m^+3OLc3P9O2CZ(A8Iu%@ozEUsVuXri0154aY1e<(mw)G$^4f3WSl!bV=`jBg_&*Gu>ElS4R z46#NQl~>~DR1yoUYN&UDWmIkp3L5GM3-Z5EVWbCktiIygU&&!bqV6qv%!^-XVvSlE zr&ZQur*X84u1q2HCmX43X-P?!Go5ETE0ALcK_JRnoK!48Gx0n7)&Uo} z(-}zp`oJL-HMJ!QX=QCKASG4KODcBwxdGFRf4ws+B9NjChHnohh{(vl^n0~F5Zpt zR-45$Gy7e1wVW8DnngDxM?O0NEc8vQ|$u=f9>7J zN@wFWAP&L7SF828!1TTz_)waRqj$0RafT~CzRRsRxZ_A zPO})`HZyFR?y~>503Cy+N!5G|MsUbAPw2+KCUivKX)X{fQsa>r@aJ3T%jp&E&ta2>1#7Rmj_+lUOP&B;Jp+xwnn z1n9aLt;KnPO+u2=s7rdK;Ot{8!Ow3c)i#W-i8JuGcz^y!BQ_x$vV06a3NAm zr7nE_D#_c2cJGjOy`lBUs)y4NTWnfGGedE`LYAt1Yi+fq%ee;n#R8Oy*H8xfdiA;E z;q@gN((#n*192T<B`iXdF9Jkf0w!hpBU()n-Ncg`Tqj7)Kf3us=$%s8*q*4a9 z;DWsuDg=XXV;)zjWzdB?OnuA>phX&gzgNPHK3w*sKNb}DV;ZS!u&!CTrE9n|j;_!+ zpDrw4Tyy~R?5{Y=t%v#I;hyVm7c^S|!RPATIGk&4T5twduA4NkGXZ%CsG7o0v?-Tia(EYK_?yjXQQnI>Z%|Cu8mHj0`4pic6np zED30#in?{B;}FHXHpT15$wjqkN>>t7aLFl0$?qN*r&`{HrF$@Yod)F}sjEwqF~g;d zj&R=dSaiRa;feJ+27*uZME9a*Ur5y)i*mT{nvGCoig`AzPevcsHcmb+xH5=O(UaOd zJlmI?ltx2Z)zVijxgD3<`7xXD4CVRNmK0>{q39pg`Eb6l^K?B<0q6t!ckz=RJ1dpb zwk9*m=x%$Zb;(%crC^@7$Ia+N0tO2{puMwFNuLLuS9T2HIY{iz3syCrrx7fNc%`+j zd^b(^81lY5hTcyXnhzWi@euNa2|*py2I>+#%@ZeY4nFiecAxSQelbsTAcDzT=`v8e z^PuBFO`^{&6W+Pa%ITr!&C_qY?KrXxUANo~LwSyp+8a&xX4%H*^deD; z{iY`$L^v3mc6mbtI#pIUJdb52g9{hXc*ge)hqQN#LFC)pvJJv2D zt#5xck`Kz#6v4Y8&^cG)+O{gQg7!9YZFALYEM39j<_1vNsi#pM?O{hJA;;x9#f8H* z%oEiM=MhpK^S^EB*_*8&+7A?kwgi+6ZWK5z5Ixo>J{4S7EJawfJD=+t)n&=8mRPC8 zR>K#IHs%o<+s}s67Gtw`)yVW+LMXNAlsJ?^?dr*sQ^dId_EAwWTu1+=cpP|sN&X7P z!}bwA{0d)kLzyani{ZA}yEcSfTnxRW7kar><@17qWRe*_JQn+Lwb!d@C8z|uZ<*Hg zfjiaj-iK9ByBbu|U;@sq<*HiCq0_aV#!0a)d}PMoAK=ZV#!eHz+n($K*k{-QTg>w?`E7;^K@I4nV4!ESG|XAecyQ)J(CW15Ub5a+a7~iwzE^!IhBAqFVY}B~>$e`2<<3n+t{bK~Tw)mEH8t$wz-8Vmls&$M`Os}iYPAOusYrnA#JyV_x zn95s7pc71tedw;7s4FC~M6OW1RKy)6*gr)lwYXC-M%RkPH4f^`G(*&LHP*4Yrc@^o z@BXNS$-q*P7pck;2{l(mp9?6Qo{jqL>5E3>1@OZFNcLKgKT@W@0@XMyjgzEjGA3v`5sV~HK!oIuSLSf!I z>Z~R>E{WOFD1zgz`Tikd{`{kRG_I~QgGb`H%YgaL>nf{>#mm*Wl0j4(Q*&a{fb4Gb zW19tm0!*7PePr(^Yi3JaE_OecHF&qyYIzXr9Z?haCM+Q8@T~I8u?3!v^AYRbTtB2{ zkR9>7&!d`$uMbudrPmA9@`SnyS@T#dACx4v?f*5g`Kym-!4Kr)Sn=k@;c4ztSJMq$6-rK@_i#;tUU)|Mnn9;`X!`#8Iea8X-{^Q z8`R51+@mKe?QST#7^8ap&E*Wb+|y zjXk@FBSQ6p`5sU@h=H!V5AxehOfuEh+L$>8!}a@}c_u`@@@`?XUvtlgCf_$^z=g_9 zOe5D1=XlO7mi6}Cd?NS@(AMLeeiN|0bSI(6!8?A$O0jQ2mDlBz`%;IdMkrxFjAf-O zKThwHYrtgTG!GF~@a#@fl{>yFnM)T}9dH3|J|>dOOXhi2-UmG`SK68MWGRCs8 z>R-VdVh;?%WGOEsRil+$Oh5K6NB5BDoYNOyb03Rc)Az=&hk`I&(J;#(s?P6)5h zMc9D_Tsc0PW>CmosYM}|gd=>=gLgyat5<4MCS%+b+p^VMXG81sCZ?qoGKuC`0L@RZ zE?<3zH*%fbuK)5;>0}3opF6bt#At$X-0Nu?NC{*##`_be$c(P0eiA+#UvNSvN<4L_t>CLlP^}gOl3oBU^wt_!)wm(!M!OfZciF?s!UC38z$!OB|WXR z1I8JJ@*@e;p%jAviOt2AV>b)4$A|lC6bSS8v1#6;DhTen(48cjXDbFS&)ubDoM1}E z>*2vfPmdKnVjY9Kw!K7hLc}!hnZK>tahP)Bh#LqcA|EW6XiaF(s4lLl`g&brg!fJF`AG!qHM^xRS)$~jZU+VLI)06a+@m*^fP2c zrQT<{O+M)seEryc?M&8Sdi5Wu_v-DK4>`P~kR{O{*<{oMw|aJDU&uuF{Z8Y>igB1( zR$UTl5J_^&HI&U^ zE`*=VC6jbgCv<{ymEK?PF~uA@8z%a@QGM`c{r$y!C4NX{=izI^lOec@hQcLU^s%{G zv!SLP=n%qP@>;n8t?MV$xt(-cJ_4h%q@cTpj|aFaZd z5GD}#gL)gQO3$?$XCVw9h3pbUf!_%5n_LasCBZ_Xiu&t4tL2L>uTTe97#ypjweKjX z!jJ{I4F*_4DY$*IYV;aUW{o+x*7^ajYKgrIVls{^zt1Rwo8U^15@3KrIsvy+x;dK6 zf%8%om+IW*HV1=dL`t3%fQoGpjc0DQ?)v>EU$`TLdy}g%{0p0q(AXyK=uaYFJ0wWX zPX&v<#1a#^^={nF$Sh_!@a2{wGVYDT5R_y0zEf1=`@4&3)Yh?iF{eJ)XL>&J1$oabuc8PC0ODC|3nmAyR3PHK3Izp0oLPnNBY_rM z)K5?c0Gn<(Ge39S2`j)#Y`>iPYqZS7aA9&)p$5`Ut!yjgAiTtwiLahmBMHsv^NvYc57hbs4Efy+qT=AXssY}nj zJj|=7F7Om-A$n}amgLhiBBd1(X`j@R8E9R&76(=As9cm17KN8kVIpLgBh)H+6~x>4 ze&(RyzxnShwF02R`_aO!mXcdutoNR+kk2S$meMYbo(i^pxz+vV)5qan!>lC9r|8>x zrLPVsU^X-ni)4|K0@u50{8j=DA3c^rGfnHP$zJ|YbLBUX)9-MX`6LzdD5S?iJke*V zhCG6%FFkfRFnaf|%s?M82k{pJESPA`KdAgYZqP9bb|Y_H{7pp2KOA!^*=F?u02oUY zq;on2+KByY2oOOJ{9T}TAYZLNcakjyUgHOM>{g}pfkwR_W*>Uk;dfOJp4oqq+546% z!$$wZXCWD-A&xJ)8m52d%Z#U9t=;wYL9>$G_H4(pfb3)c18sQ*vzv7_kR+vrQJwnz zd+5VL?MEAwJGKfEH8GM;`w@eSlEfrb73&YWsMN5_3DB;L&-|YGkUwc5SQQ;*pCMZE zJ#Lsy;=$MHdBs_C+gID~EEt$th63HAooqSg3>WIl=sI&ta~8gKXq|gS9DvM>!`_Z7 zEi*Cecd(S!K4Kx=y(A&Uow_^}iqFKVs0AyyH!r8VH+i-%QFSn$41E%~UZEHv=k=NfmN?iAn+ir4WM!RnGkJyH&sjbhg}(Wq5C$uNGVs{GU9n!HwFO9ywdZ*Nlyuua z*vFm0Y`6*}O=QGctQcFEiTDT@)W!P~DpTL?&H|Z^UWDu|y3XQ1m>5j%(Mk>DGGHdv z#SDcM$1Z8_wp{df+Nyf?SG6S03p#chKJLxlu8VW-cDB?*I&{WuWuqp)K11A92^&pymHRfTl(pfIpp=(^bT)VXOD$77ot>kq z+2`5=Q?;`iZViKXzc^Aqjk3e#6)i{8p{!h=M>9PPk`b6`z7~BoydqC{H$|X_?XQxdwoR6C54--Oza^!_rfUTqYP2ea~RUG zXV(bGjsdBny+XWpx>Rr89QV&mT-U@j)!{&QVh*Ap>Mj84mxOOrbg#+M0S&A3@}kls zT20OetoX=v*;&nkP^D^1{%t?WSO<==SJTH6VG3iM-I7n6qAj@BmBqRTYC5&OVR}kZ z=goEuO{L_6jRnW$J_Zxm)OYuyHQ9TSTq4VSln?T>la16Uj;^7gm$n1mSsAG}6n;LW z@Je4|m@AHbdd+1{`qRzuW{(GPN3-nZ?oW)GIu#(%8 zX3JK_7D&bJQ21q#Ex)Wd>lcwP=Gh-s$PnjMwi`x@1Q#w90Y4EOn03 z@oqWjogo72mEYqGltIG8tYWOYsZ-(s$b^~F6loOBPFIEgAzrqB{;aQ|jku!deh-T}$Uk`xTt z75%BX&*AHLQ-A^nRWLUE)5lcU%(VeaJ|QU|&1KD10o>Si7mo3#2H!*OH<_zts@)@l z*--(PT*M>8RfK4l9=8k8C4Tl`Wteqk7vol^;QK8T^5?kD3x^L591b(Mj4r>ISo03c zg;6oV7^j%J31_;p$g+!gD*uQ(TKMZ@P)4BIu!WRi*no2U z^qXFNeCqJ7e|hGS^B-pJXc5Qjo2^Jnv*^3jClG+MdMyh>t^Np4)-gF(sMetpIGzGZ zYs+&QIjWhjRtz4CKD_$0W9mhJ^qldUES}EwXDNqD&r8m2F2th0V6-!+dGY_G#qcPG z>@};!3pMW~C2*FK#W^1=sQ<;u(7lz9H}{~3Qc!8oDAU}}5LkeZq3bkV6w5EA%TIJ@ zJg=YdB`C#NQ9ULsU1twdwM0^$s9;Wqh_xqw_xH^s%{B}=R$wLMSAQcR$uoMOFxBA?fkeiT9@c&BK|gYj)cfxzbs#kXPyYr1x1mlDeEU0IWbb*wIa ztb1+5QQnlp_CtWs7kWnw|H{!IQ-_!!lu;I3>6_lSoavFQktL4MMzsr2(%C8WR7Na> zsjf`PK?4@Fxz7p;XBc{t8d1ppcd7%zZCSSN3|S0r&c2DDaHDxNMYC`Cv@Nd&QepGF zUxp#1AMc}T?{sd6<6yAa`&yX{-@7D|``oI`(oe{HzHjzJGAOl}STfuiJ&hrHk;w}Q zojFs@np0DP3AVjSpIzhC+zo5T6r32CsHTtOE4A^5_g~{bKv8t0A2cgJm>@du0plDD zssGBG)0Fe7yY&=M6PtN54yoRoQ9^Wf2;llc*$4VoSM*19)}*>?Kdtu*SH<|)b1R0y zk~PVG2cAexqD4iO$DS#b(y*A`@|y6;(C2Pxht}VWR<{0_d5$WYtf|8Bs#&+ z`K38#UnREpK;*P9yK~)>`RS3?#VdJPcm7NbzI-~cBWvX&8KPetT2JU@V80@sc7)Z{PM4TF zJj`Z`#^6D{W9_TD*0X)N zwL7#pg=e^-_p4L>6i7iyxz4`pF{h+Fur+`0J%f9c0R0Qp2>x9IO=n1E z`=!BD6=S@FFqT^zSzYXuXW z(x5_G$hYVu4kAF<3Qc~qW;^Y_@Y$2h?YVpZU}{pb2bhk93&b8yD;lZv#|Pq!j1#6f=bI3A2{g)+t@QwGaB7oob;?hyo+a_GE*mi0 z!*4tnd&?K`e=zmt@ld^Q{J#5a0@ zSVy+8Z!w6NVPeWQ7)xesGq&$hpYQMY{iDaDM-MvZ+~>ZpbH85K^SUo!wY<1LJib8w zVn$+U;L5*18@as#L}L?_XFpmT69xE?ekfqL{cgLvy#Ew@BckiFT5|P@|lAp z<)@ajY_#~A=9q;INBsWR3S2Tjub2~%|4lCdz&;u)wUBG4h7@~xRiu$E(d&t$cv{au z8Kn40RfeH8nR#~TM$n?f_J7+nNO{wC(*77eGw`>PiTYlJRNz-b3o-w6!y< z#6#$t`PCdO8@XyNRaD+-UzLVjzk!M^Bgn0G@hN@47z?~_Uwi0n^3mt{5(1Yg8K@v&APt$UTj_Ask%O)(k$z*Ghs(hM z*!2L5ETQ$vXTp~$#+9FLL>FkR4{h>~nnricBo-^LrB3`o$UL<<`B7{CB&vEXmnj^dYe2sW2CWH zM%32~7Kdm~rvacuo!u2;-bMmRdC((t=9Z3Yf{;x)CIYlr97V z$MplmT+W`9V-UInwY3}i8Wz;CP*^r}^AHY$sC%8bRVtm1b=SxWhV)R>YM+;PHVcjB z88&%2HMiWU_kNT+;7;nO!R&r|U*BX1mlK{Apw$*`lH^Yp?V<@81E0Ab?ltdhl43$~ z#-OyIZ6FV1N>CWmbg|Ump{MNnS}1ACS4Ih5OxS`iweSx$E>v#3yebf1rj|XZbKv$q z=LcUHdE{fJcGBh8dov#EfRF4j|J&A`m2z-{g+tMLxb5bo>mdCZr35z^&EQ7O7;KvFRSqk8wkI z$Bn1JD4YLS+cE!auV`Q)s8G~{|CEvE*gSm)=CJ3lJtotPBxxSy!y7;L4Z*E!9giWn zILKD{S%WeFg9^R!sBy~Z=L6f%iaj^-Fu`NMv(i3hUey3)UG`6ZY5&M#sJ}6cHgkh? z!CcW`{Ob!P65rp@#}8y={la41pxl>*8$-5kc&F-#CG2T)9~?>=>leQ{@yQZ6 z2Al55Ydq>_Wpv4yoT1^vlDS>C0Mx>Q^HXoB+NMV-&G_oeDL=dP1>X1mbTx@%tt)_dYx4K-U}h_V*J7R|@BommFc zec}N+?kE`kMh5t~b?Noyq7Y5e_ruJ*`g*Jjj(LRrdxQ zndceOww$e4#Sg4!lmEMu=V)zVAS+yW6#Qw}0GP2BnB(=(@1C`RNxie78vt8t0#mrUPtXv%;;byW5;}cE4B%x3A_@}dVyxY zuLa-cUf5*&$03cw{V?zQ*7(((y#wo^kJz*{EUmVAQ`o?I+AstfHt88~Rh+crf73I4 zNQpnsmi)pRKM;T@LtPe3Ba@w`fen!yNOp)diwpY1r+~5xr1VUuHJB9dHlOgVS?{tQyObfGu1<%`56g2RH);Wh(lDR@4$73{ zI_7JXkK?KQA1GYt4tShH{o~B=h^MpIe}O_tESA zoE?k@hc_UaQz%ND!{8o_RyNr5U(;zIWzEBI5O+B~1hqgwki=w!e#j!7V(T|h^`mO) zE8NX^HO(*gdZW|U_i}o=xsdnk7r1|bPLHuHL~R0`pm+VxcVj@JI0B-&)FK#RE6y3N zWorf--fV0xQ64el!1Yla=YI#=zfuFudz%BbEC7EXptKA`%Jubvg(%63Oz*y~=wK2B z%p#~O%;D__x45!ut;kj8qM%GFu{o1@ZF9pM;(A~4{zbji!Y@;gNaV(nkUyD4Lz-pb zLq}WyMu2xdt%E3gUmaUD*`WLcU_r#(Qh~hpTG73P0sts?6>lt8-lmaq#`*mB;9`W# zrX(!az48SdFwvGYbBTTnS{wB2tW^uQ$fRVc?j?@u8_9mD8)3y&*F@cQj*^Qj*%haJSrabQNFc zM*!+*DDA?*^&OAvHIA(1(=q^%+TPy&Q~{n#H7#67ra1_>TkosexHoj=rU3f!<>__y zgl876b@=OP{Xercx_5#A)D9qVX^*ap9p{Aq&=pU3Kv_%j+59LE0K$gU0Q}&oIiqGf z87?n^NG4-bkCWb}C@a|Fzt(R%T>UE+^LsI>; z*tMbrMkz4%+W%6FtGc+*x z#w?w3-Tu0Ysa>eew)BqO(aoTs7n=e?5h6aA0AKMd_m{etc1qY*O$IM-q3q&9@A=T|p-pI_zsm_wb<~H z&1Gf#&fNRiOJI|5kV|fAQrpR<>p7gkV{_%v6++ySeydqrc0bUyimp{buI}xf+h7>Zf{rHGoZh@Kiy#7V|p870`CHvm~CCZZlhz)V)ghQ z3*ZR`z6}b0lU`xWZ()S}%u_vfR6qs{`)SoE&`lE_RSXNqrX#A>@6w`Rnx(Lvc?@A6-441%D) zLAn%X4{vGb$#DBK;EkYg$d!YpP~_Y1IU*G?<>o)UT0OHqgT614t6S2JubRBvWk%j) zJF0D>>>U{=i8MpOLcuE_i6I}BH%>g|kjkFKgY$of)=Vv9FQ&sO(BKbqynqN~xUSJX()vFzdA3Y~0SGym?sSQoM6d7iG%o|~gJq0GYqr1fJzkh51 zJoSwrb_SF*PD8?j7gcixAI?p-KciVGrC^w`()Oo42uH>myn3trJbvxL%YCe zcPjQ@dBocJt=&M}OAm+K>nK)L(f=O5U^$HqQaG<%aG% ze3+pJV>b+1$y>pr3NAnG_k{jlA04HoHnDAEbA9EihoYj#Rhw{a77EK_I`6)<7aA;w zRqlh~FIY}&_z2p$P|3Vh^20+e*oNR?jv6hNkjQpKIWij5p#F};fD3I`rwPlQm9<8!in61AGfgmtoOS2)u-kiQWYbg%g;8Pz`>`Q3uj9e3SKIyV z)qnbExh3s%-l1;Nic`avWRXO*AuNmw1UawhqZWr_9f=p3D&mQw4+G!;Iu5Q!7X{?Ha{Fy4u8LA~GV{1u98`oo)O8{l5Eqn(zNE-uZq$fL!b zxr2~xaDSNKzRMP0amGf9ssopIIlty*ZQT5;8!o4TDfaTt#FqM=6|Zk|R6&#;!R$g` z)k*DihvH2u@f?wMTCt>NeRTf&xO0uq4CVEzOas`38lRao`6k(LRi8^L_0zg$-gQ^i zVdE0sY!Z=n5nSp0Aah|?w^zYj%oo|18DesJ-i1?@Aoi}8fBBgg7nk?O1fj3Lg~|-0 znuUn1&S*^^JUn8Ct+O4bWW)Ev{;Np~5HNfEh&kin42wf|rZB40KS*cj>6l6B3yO^^ z5Mzs@`xH{PXDm~}`%fpiT9VMNYfs-meFJ-!)ev1(N$B;tmCX->=PpfJ$(oqx;r*&^ zskg~gEe}64)h{O9i~jUM7>uzF$$}(D>5kS^J(Cd~lFvwy*Si2C9f-0gmLLjC+%wYT z`+QW4kVdqG22TfblbczXf?l5$;nKJ^;0osEWp!17_|+t_ca~C|BmT_;-;ArI3i+3H zmWxtLfSyN88F>SRq{cdp;HN#J!oV+!*j^Y{iI~m?>t>4Gl+@RIVkg0#IA4`if^Y;$ z7E1Lut4@qcrPZYCCvjDos_O~6K7R0g094u+m?$DEa!p?kVY(wKENm{Om#Y7%1Jh7- ztABM;N>2pCT;EsB?3$|gd|(dr!-AkNqByqP;&yGdi?`SsE=trqde=nVJCf+<8Y+PA zKb_tiI@E{l>>P!Eh$pBH23bLPCQ;J#a&cDN+0k=pl8qHJp4wQy?4V!=ZU9N5OE1eb zDD-lx-=)USW59bGRfIj!I>t*(KRawucl%Bn?a`xJYwQK6ry9+up{E&pr zAlaCPL=ioQTw=`~_t64xwB>_bM`MR;a=wML%c$fAi0F{9tK~@yQ?7C;2I_CCEHDhRp!jV%k1{xVl*_>MVS&d#VL`p8< zooZ+Gn?Ilt1*K^tGBSnDucR?u?!`l3y+AbW2>Mcnx}<&lCJNPP7(!b0`azKcCHX(v z1L(XUOKUo!R%MhmYuDGR2bRI=#^&Lz_V0a21Yz}`U%YwrOI5g^km_0gCmK_i*sxmQ zYN0I6+z>E6SXHHOf+gE%Bny-`KUW`97}*lmN##(9u;TQ)`cA}nfoBhA^?0oO2Sn1D za>4!?tS|+&?vTs18-2%IF{!ZlqItBH!&q^SbXuv2mWLs#h!o&DX?piUMv5{=EQ0)? zvh422U84u^uJ`%Al?k6DM23tJdlgCp1 z^LpR64BsHx{*u(Y7nCznM%LX^L=w@ig;v@6W@e=IwZO#SmogAwd`UGDRtN6b@)h7o zU4^NA86VbzCBy}fZVSL^@$;L>goORM6;rsV;S*Horhr`O3Toms2=z;?akk@ld)(@v z3R2OF&d3g;S&$b;36m`njY|BNg@dqtRV9Ta6=ikxAQHrG(@oa|I|7Q$&dv378b*&D zCh3}(jMT(_(76UnZQg>Kdl{mhJxFx~mNtC;n~a}Te^tqxZ?Nz+i@oxOi+k3~MdlD* zl`Or~a#QZ6Ex8|1?|MsJ^NYrFrRCpo0`iIdG5Sk|X%imZfJ5y;$2#P zPD3b;w``3l)%qGj%1udG_h?0_=ye3+Vt^}W+Q?X%uvMM4)s%_;QYzPof4B3VX(mN! zq%PKc_+3qTO@GXoKWyH*?()+nwRnS*=2Weth44*7X$bzo6k@GhdK;34G(EcHV{hUd zQaf@Z%{Tb^(!PO+o=8?60>z$#5tV!>qN<#{zw&)7giTa6NTRF5-?Ws~D-i`LgjgiK zGZ(Nf7YlpsY5N*GcqZG`U-EBAU;6fW3?w*j;O&G!MzbZ3c^n#vXlB?Z82Z2VHMy#X z)z!$eKVPdq5&fff&hZ-T-b=BnNrZI2sqdJ+0j`nu zzWVbIktFBBxoQBH`lzeFM6)JOxV4@zg^Bj3B@yc#9EE&y5StGkm-#-Bvv;iK*A52) zl#Y4Th>>5&l&;mz? zN^*6+aMSRTX5+qF);Gj+-6v+oW2JZ6sAV4%^!)QWaWT4?4?wDk1-NVic1PGX^#Rly zrGk8jK%F*tb+JX#%`OF@J4dKgev&y>Ss?-4BqYgAQO08)|8!1C@0wN_{; zP>*Ik2^_}FxH=AHPrR$*TJnH4@qR|z{)@W~&2uYnxL(H0RF`H%Grh}QV=)RUO(}Wx zZi>+la`n^8&V-KZ5lJRQcLHbx>{k`0JNkoEK6_hHzi#pc(p~2*ywNR9)zz<-Jq!wE zF-iI0Sbter2x&QQ!T$XOQgxWooT|~MGoqG2+5Ylydg2b!H%CfFR#Y!(Z0&Nz^kn?l z6QlitVg;6ZWIx( zMpiX!!aeb?(^N(Tji$_VCH>co?#U!;$BPrY@vn3GWJ z$Kd?YA7Vp3C^4U56RkN5@rcD|Yzr1O(O$_D?{i$WZnTniM28Q5hC;iKmFlSUx2Jc7 zK6*UX%fHMyiR+3NiUoF_Pg?C`0Fm~akKV4fZ{Qxv_DTc_mIjY8oXKPW$k*T8?I1v0 zap1+uwgphkhju+|elv-+@_+AJY{8o3>**2w1CS8)YfR`;>94oyu2_C3bbY{Ll~26% zOFS68+7Opf_vR$vJ$jJK0X)J~!7vPY3NG4zbHB4s5`w>ZLh`m1cJb2bsXL*74v0E? z;`j42SvXK}36u6I8ppFP688;V|Yb)+y7I)4H zfc)xGO7M#GFisT>4t3%IN+avjj-uT-}b36ucS*)+`bWgDI?6;7ep&Om<~ zsM@(0B$nX!+8C{3^@tJR*3zL?CR2sT@0X%>qjS7AxHOUJ&Y-X<*59%qSZ?x@lX9Ja zT;u;hR6e}m5_W6U^I7$IZIpHXITdf-$iJ%7;=>#82V35iDt(sk#q8UcTFs!Ykrm9V z6z;4FT3ELJ{z|-&K%4Vx?og6j2reR>JG7Dc$?=)5Vlp-Cc-~C|RTYK(cA%HJQ_neE z#Eb`r_S}ct-+gN@Cs*TFK)QIL6}z7ER1v@xxPBd%UHR5d5YcDQ0Az#f(-$;DWUv&w|kHw)FK=ObdO4oDr0-?W=5=T{|38j29YrQNLM~0GB~#FSwnv+7?_)x}0?@ zGcV`D%*#`#1+Pp-jJE?$lL`3nr;3c2rbvaWa*8JRau&jJh(pZAqGp07M-Py z-F}Q0H@+BNaR0}v21j0xQ=&OMwv8{w2^Emn**C|*tvftq8D&Ra6_-c|9HaHw_14fQ z3y%>6QS7}*K{C_(zFL+)G^p+TQ_Jc{ntO70d3}KrA7D$3>t%OMC6dRS^ZK}k2)a;m z9Q+82zS`F>J6|n}PSw#&W<&1U333UHh-lbrt1Bm z0KK|kgoz;9s!FOuh8~rF2M?69GV$dn=>*g-E0Qv4tf$`P@2$Qn-J>1xOF4 z5mRQ^)+!b_l=<+q`NC&oF=pz#b6$T8CHyhZ7-|g@BBOPCMzRS&qu*-Z~ zJpUdakL&i1`~8q7lXOttzo#-9aO-&wQe9-ceQ%esr4L@sN<_xpB`rPxdacAg5*j zUan@ywWXCeO_V=R2l(kd1Nu3q+@dL8J+hPxwev4m#CW!aBhPDVFY<(3BnRi05YN6T zI|!5h39)+cb{DxtT9SG7Tx~IB_Y7E2C+D!N=TJuy;iy#W^qJS{m6nH?JkpfAU@cd*X7f z+8(XGY5C!N&W>QTLV1l@1ESfjkBx4FE>zgfmmyAQI|AIsz+|oTr&f9 z{>#H^X)%04vmP`Kej7Kckm?`DKVKyJMHKGAD8WhqfAt${drGkQ9nHEF3D zJB0OvK*nxvQ-EIG=mPvx1;grK)WY6YtpFOavrNm~I~*pZ%PtWk;buYi>ty(8`@=g+ zL@TfYIKEzR%B}=rVJ?$4qHw%3W(-o~R23pT1)rq`JieH_4zO|(pe^ds*1%Bdx=ZBO zC6aJeE>H210Hv$TPRPW>oIW$3RF7V!ed3j@B)HQ&2e`Brx08Q1~$ua%d+CFiSMrffm-*r-maj>g#9l*mXl0pmjp zsJBG;tPSsJqdEF#i@e_T(#(4_ybgo6q({fK(YT$1fJSBcR6E%47QZ}nvo<)5#~n}3 z4(=YHEN3mWc=fw49E8Jtz?k1|Z_|M~Jq|xBWL_38?~@;V`Asb`3&WaQb(t29Mpiyw z*9A+J71-Q)pQg^!f?r<_7qs)`1_2J?T*4B4rvnt-oL2HPZ?GS zp9WAv#slCyVkunZF1l1kXe5GoRb-O9)(g@TWpCiL{Y;!KGrIJ2-Do{RVH2>tFnu4l>er^B6 z#DtA=yHE?^0OCZvyBLsv#CDJcQ^yLd@m$jWJui@(Q&jxaM3jq*i@f;#Dv6d)5Fm?E zf@|r%V*^40TI>;Al$_yp!GLLea0{>M!nmKxM~y6uRGZf%wwaJ1>#17yv&rkgAFH&r z(})!e&=4ZXA-!lt_(YHcaN>wQJA1|ualBd)`I#YYX|M7ULMU)~4`ZkCgME>f7ifj` zA0X8;{6-N3DH!xRHY_7vK%MNpBm?W%%1Q8w@Ya^%v?3@3^}R12u8ul5d?vs;4_n3E zQdTzafvnVr!{vS$dGu?`5ulW&36#h8>(B zo&5^i!ir%hZzbG2Q(M14vQmgtJ-_Pq_L1k!^~d;+z!5B87NX`ckRh>)*gY3kB_vzd zAV^*9V%Bm@5TQSYOLlH<&Otq0`4Waba9pmr0hrZyrawuHhe_Kj-tXP9Z_)f9j(L~v zDImb1stv<5O+P#L89RFRo?cRK*lD)yaX!Su3lPJ zk<}3#=(TrI$9630$rzvZ0bf3jZC-f{1uPK{P&KXAQ{N{l>VxC8>WLK%-<;f--lJ@h zz9XAMQAyy)UOI#>#nMPX^TYlYFLfmi+?z$Y>%?}mm}Uz6W9m)!y9;ddzspk0WUX}x zL-VS6hmQuW(TPA?O+C@@IT%#*iW7Nr>4~zka^fe6xwf#=?rj_#Q+P&SgEx+x(T?T_ z=E(dwM7|Lrf5?NB&P&O$KONRRee_5iY+?e0o$Q<(eusDnKWF|ZH1WgR?4+Q2drIMi@C_Xo%oG#2zvQb*DPFv zkQvjhmSv?WC`lJ@+m9ns)Y3{y%9?I2P~+dFRBr#oa`kjl(c7h@=h2^@`6Jl6S|9b? zlc-zaz&6qr5G^4!xnG|bK1rP)CunX51OGJ;Q-HpGy45Z{6McPskAZjuH10(GBvML# z-@R*OWYqK~mNd*~f3V-6*rSozzj{SeU7deE>&bV%$j&5I%R#5=tp_=KAC*zHkMV0@ zvmh6Ate^1u3?6tw1dXUN`4d7YPCoIpCnq;IAS`|lmF$1Vr*q9eYhidybK!3DUV-v< ztb5J}C=|-MqJJxO0Y|J8d~VT$a7IMsVw`T~4K=^32EwX#JABC6nSSkGsZ{(A zz8xOMlIo(6vD9!tZ1#2dgH`S@N>medjF(C=y{bhI8YGV!B+*M^s4%i0S zawIvDyymZ&#HL~St(0rMKc*iz;MxlTZ0i@EXnF2Aw=_=vw^w+cCrokozvNl~w6^>}c)W1`M zxsfjGW3?nCjy>kG_5unT>Grj;NO`+CwXvf&2zYI3F$fZ{ zWjek3(rmIX$bKVXZxq_gmyp@8z)fqk+B5%Y8HmrE)%a(A-8-qP93nzEiWThZF%)-A z)i>uH$=h#Gd)0DD&-hxjan;=dsfVI^@_nOs3jjRxvtVxrB28gO)nP!>D>}$|VM-|i z)%*&-da~nX7@-xne{zm%-+?XM(PQjX=MV^d;tHYNkM@rB)-T!Hsx=`9(cn1dzZnpe zR`RE8{l}L>%m(HPDhQ^xs`HZ-QuceDe>FIVwK_qI1@5wCwQI9kIluTObK79=bwVvIK2s1=730)q z)?0_4aRz1CM(Lsp?``e@BJ}@DUQcY@*sRleWK8|d17tn^^$2K+Tn){8YagXf>wvbI zwS(FozUEdj05ogx-uvU+*{Z~{^@5p zv0eRJgwR;lNn62vM*~k=vI(%;&vfzFW2q=Vu+rn{e(I(PD!&%-!)QZCp6_Wk5h%fUD1|+JbFQ>fvMz(0~(?eZe!& z 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

ptp$vc(zEtnZVxG&ieG-?=<(0BP4Oeaf1B0-(7 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 Zw4iBZcp|YU_%Ltw%19}`ESE6y`#<)I!s7q{ literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/publishDataView.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/publishDataView.png new file mode 100644 index 0000000000000000000000000000000000000000..993610c4db802b7775b98c3ff3a28b2f59d5351d GIT binary patch literal 36622 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/registerView.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/registerView.png new file mode 100644 index 0000000000000000000000000000000000000000..385713e13daed2c04b45e7625146e8c8e794b03c GIT binary patch literal 17868 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 z literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/selectSensorView.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/selectSensorView.png new file mode 100644 index 0000000000000000000000000000000000000000..94af4a48a024089aa24fd6d5dae0c77af22eb307 GIT binary patch literal 38015 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/thumb.png b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..1524c56fe77e4f59ccb87cffb7684dd1c5498795 GIT binary patch literal 7888 zcmbVx2UJt();3Lw6cN!#M??@6LTDjC=m-%3Cn6vvNC`D0lmudE3IaNah$tvk5X9in zl%kM;h!mwmsG*}&Ly;yR@EsiI&b{lO|E~3YSt~2&?Ckx%yFTwe``o!?Zp?d7_#hJ# z6EDKV5Xr>EjN1QlvICUXvq8eZj}YF-27ejnh7WS`M>FZU;+)Zv2p=bRG!pIPdfo3M zT8oK^)z8z?25)0_QNso2qu{j9qd@fW1*Dmnv~-BRPA=YPyreVQ-4hF!TCA#(lJsFhmEq_@aRfYE3efaV6MTHl%>K17HsF_| z0GEM@PQGA>f+E<*XWy=$+yQtb`foMWwqQB(hGoqv*7Qc}~`H`IsdsY3N35F=HXAxu$SRUM{mbY2~*ZUFmB7J&`G zJ7HbWf9>rF?EOnt@xRJy82F=|@Hl@<91inW7F_bc;c)>TIA2Kv1Ig3Yo>*60P=MTi zg#I+x5bf_7h;}{ikMoiI>0%Aff7l+4cG|bkRbJ7_$xR*&Q9;W)E32!?yFuNYm7vZp zXb40_>X*Fh|J8M1Kq>Hkp8Q+h{6zwiasTpPRRG-ltB%lEpm_X&Dv7^u^^}Q8cnx8w zXGt9VI?SE+h>+g6y!W={i=sWd=wtTi*rx){T>{xTFW45&6nF~T&8DEI3ZJZbHJchi ze)IWaRsBaf{+Tql)792bW<%Eu4%=Kic;U0ur&G856gca60;U2Lwzt=QWD?cecmlA> z(>$3Q^J^~A$^mX|KiUJTr}utjPH*moE)$2Cn6~a^$}llSfS5P|2&v^}VgobX7(1{} z&|PBrM}j1g8Q{2~tb1Rki7&IgZyv{(2#}D!eeQP9N=ZDR63-PdzN^r6*JY3XF?bUbeWWr)FKgKHw^BL6T1`!dAdZQ2L z#_@Nq2WnH3YpVhogJY+X?Z35UXJ><(`-*ZNbvWAE*=6>Z`_NgTL%wxwm6es|A{6W) zb@L?w3ab=R74P1j5&CF!aj!6hA!^IHQ&3Rg<3J#+B^TE0ZuuC;i!(a-{4B;zt@tUM z$0*gl>LGr9e#_7Nx9vQ|J|7g@2%RJ6X$LpUS5VIEF-m*T-ya-(Qm2=u-88nfwdKz> z9Cb^<-wc8HnD#bcdIW+Sp&%zk`*{cL$6ACVpy37fZ@Y9{o9=H4R4zVOy&wCjxfw^D zFRW5{U=fS?&W>3UsAj{3tp~cdJpRq<(xoLx3JXkxB`kc|2;@+DZK~x7wy5IWk!nfe zN_$hn$vk$Jn?j{*{#UPF9eA`d-JW?Zn5rj2;ei3V4@{P2HAkIk@-#9sdiLBbH83N@ zw#ApVHnlIyJ2FVg>}E(m3cZL)bANHd<2V*r@J(p52m9y9iHV8BQ#1%lhl+}TItEjj zQ&A#eE%(#-56+NDE_+fH8xFNWx*0-u+Zmy% zmAe3WmCpWma{ZZ0zq0L}?mK)GO!8Q)k+85Z3XY%Y7}1p+v)0axKTvo-$wNgrfgz_D z__co}hF3(bt*@u6PmV*WaZil(@`DEt#@fTy zUmrp&-5XysUz)J=oBf=^%E6bW*d{=)?DD3mzoa&Ji061se7JMs`pNh%0XDF}jQG>9 zhlNGnFv>N2IIB#3SP?i|G#XtpG2tAMJZ5AqO>|Mi&~x5rEX4^>OjL=crlyku6fu

kKhaelc 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 PcgzSQbHhUYYZ3ngtLSEh literal 0 HcmV?d00001 diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/download.js b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/download.js new file mode 100644 index 000000000..f963c0e0c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/download.js @@ -0,0 +1,180 @@ +/* + * 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. + */ + +var modalPopup = ".wr-modalpopup"; +var modalPopupContainer = modalPopup + " .modalpopup-container"; +var modalPopupContent = modalPopup + " .modalpopup-content"; +var body = "body"; + +/* + * set popup maximum height function. + */ +function setPopupMaxHeight() { + $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30))); + $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2))); +} + +/* + * show popup function. + */ +function showPopup() { + $(modalPopup).show(); + setPopupMaxHeight(); + $('#downloadForm').validate({ + rules: { + deviceName: { + minlength: 4, + required: true + } + }, + highlight: function (element) { + $(element).closest('.control-group').removeClass('success').addClass('error'); + }, + success: function (element) { + $(element).closest('.control-group').removeClass('error').addClass('success'); + $('label[for=deviceName]').remove(); + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); + if (deviceType == 'virtual_firealarm') { + $('.sketchType').remove(); + $('input[name="sketchType"][value="virtual_firealarm"]').prop('checked', true); + $("label[for='virtual_firealarm']").text("Simple Agent"); + $("label[for='virtual_firealarm_advanced']").text("Advanced Agent"); + } else { + $('.sketchTypes').remove(); + } +} + +/* + * hide popup function. + */ +function hidePopup() { + $('label[for=deviceName]').remove(); + $('.control-group').removeClass('success').removeClass('error'); + $(modalPopupContent).html(''); + $(modalPopup).hide(); +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + attachEvents(); +}); + +function attachEvents() { + /** + * Following click function would execute + * when a user clicks on "Download" link + * on Device Management page in WSO2 DC Console. + */ + $("a.download-link").click(function () { + var sketchType = $(this).data("sketchtype"); + var deviceType = $(this).data("devicetype"); + var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link"; + var payload = {"sketchType": sketchType, "deviceType": deviceType}; + $(modalPopupContent).html($('#download-device-modal-content').html()); + showPopup(); + var deviceName; + $("a#download-device-download-link").click(function () { + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + $('label[for=deviceName]').remove(); + if (deviceName && deviceName.length >= 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(); + }); + + }); +} + +//Device owner removed. +function downloadAgent() { + $('#downloadForm').submit(); + hidePopup(); + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + showPopup(); + setTimeout(function () { + hidePopup(); + }, 1000); +} + +function doAction(data) { + //if it is saml redirection response + if (data.status == null) { + document.write(data); + } + if (data.status == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showPopup(); + } else 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/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/jquery.validate.js b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.hbs b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.hbs new file mode 100644 index 000000000..6548564fa --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.hbs @@ -0,0 +1,337 @@ +

+

Android Sense

+
+
+ +
+ +
+ +
+ +
+ +
+

What it Does

+
+

Connect an Android device to WSO2 IoT Server and visualize sensor + data.

+
+

What You Need

+
+

You should have an Android Device to get started.

+
    +
  • + STEP 01 +    Go ahead and click [Enroll Device]. +
  • +
  • + STEP 02 +    You can either scan the QR code or directly download Android agent. +
  • +
  • + STEP 03 +    Install Android agent into your Android Device. +
  • +
  • STEP 04 +    Proceed to [Prepare] section. +
+
+ + Enroll Device +

+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+

+
+ +
+

Prepare

+
+
    +
  • + 01 +    Connect Android device to network. +
  • +
  • + 02 +    Start Android Sense app in your device. +
  • +
  • + 03 +    Fill login form with the credentials. + (Use server URL as [ https://<WSO2_IoT_SERVER_HOST>:< + HTTPS_SERVER_PORT> ] and click on + Register Device button.) +
  • +
  • + + + +
  • + +
  • + 04 +    Once the device is enrolled, click on [+] button to + select the sensors. + + + +
  • +
  • + 05 +    Click on [Publish data] button to publish sensor readings to + IoT server. + + + +
  • +
+
+
+ +
+

Try Out

+
+
    +
  • + + + + +    You can view all your connected devices + [Device Management] page. +
  • +
  • + + + + +    You can select any one of your connected devices for available + operations and Real-Time data monitoring. +
  • +
  • + + + +    For historical analytics of sensor data navigate to device + analytics page. +
  • +
+
+

Click on the image to zoom

+
+ + + +
+
+ + + + + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + + {{js "/js/jquery.validate.js"}} +{{/zone}} diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.js b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.js new file mode 100644 index 000000000..6f277602a --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.js @@ -0,0 +1,26 @@ +/* + * 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 viewModel = {}; + var process = require("process"); + var serverIP = process.getProperty("carbon.local.ip"); + var serverPort = process.getProperty("carbon.http.port"); + viewModel.enrollmentURL = "http://"+serverIP+":"+serverPort+"/android_sense_mgt/manager/device/android_sense/download/"; + return viewModel; +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.json b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/org.wso2.carbon.device.mgt.iot.androidsense.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android_sense.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/androidsense-plugin/pom.xml b/components/iot-plugins/androidsense-plugin/pom.xml new file mode 100644 index 000000000..59a343d4c --- /dev/null +++ b/components/iot-plugins/androidsense-plugin/pom.xml @@ -0,0 +1,62 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + androidsense-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.androidsense.analytics + org.wso2.carbon.device.mgt.iot.androidsense.controller.api + org.wso2.carbon.device.mgt.iot.androidsense.manager.api + org.wso2.carbon.device.mgt.iot.androidsense.plugin + org.wso2.carbon.device.mgt.iot.androidsense.ui + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/build.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/build.xml new file mode 100644 index 000000000..a877b1141 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/build.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/pom.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/pom.xml new file mode 100644 index 000000000..5591c22e5 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/pom.xml @@ -0,0 +1,91 @@ + + + + + + + arduino-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.arduino.analytics + WSO2 Carbon - IoT Server Arduino Analytics capp + pom + + + + + maven-clean-plugin + 2.4.1 + + + auto-clean + initialize + + clean + + + + + + maven-antrun-plugin + 1.7 + + + process-resources + + + + + + + run + + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/assembly/src.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/assembly/src.xml new file mode 100644 index 000000000..a5a375010 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.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/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml new file mode 100644 index 000000000..28b710c27 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..25df56734 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_temperature.xml + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..ccfb3b314 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_temperature.xml + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml new file mode 100644 index 000000000..d06f73b14 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.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/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..27ec69702 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.temperature_1.0.0.json + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.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 000000000..5d94b9821 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json @@ -0,0 +1,20 @@ +{ + "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/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml new file mode 100644 index 000000000..41938dd4f --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..9b4228e30 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Temperature_Sensor_Script.xml + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml new file mode 100644 index 000000000..c4580f909 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/pom.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/pom.xml new file mode 100644 index 000000000..9ef464d1a --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/pom.xml @@ -0,0 +1,170 @@ + + + + + + arduino-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl + war + WSO2 Carbon - IoT Server Arduino Controller API + WSO2 Carbon - Arduino Service Controller API Implementation + http://wso2.org + + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.arduino.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + arduino + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/ArduinoControllerService.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/ArduinoControllerService.java new file mode 100644 index 000000000..7c5be93c0 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/ArduinoControllerService.java @@ -0,0 +1,300 @@ +/* + * 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.wso2.carbon.device.mgt.iot.arduino.controller.service.impl; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.common.AnalyticsDataRecord; +import org.wso2.carbon.device.mgt.analytics.exception.DeviceManagementAnalyticsException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature; +import org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.dto.DeviceData; +import org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.dto.SensorData; +import org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.transport.ArduinoMQTTConnector; +import org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.util.ArduinoServiceUtils; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +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 org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +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.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; + + +@API( name="arduino", version="1.0.0", context="/arduino", tags = {"arduino"}) +@DeviceType( value = "arduino") +public class ArduinoControllerService { + + private static Log log = LogFactory.getLog(ArduinoControllerService.class); + private static Map> replyMsgQueue = new HashMap<>(); + private static Map> internalControlsQueue = new HashMap<>(); + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private ArduinoMQTTConnector arduinoMQTTConnector; + private ConcurrentHashMap deviceToIpMap = new ConcurrentHashMap<>(); + + /** + * @return the queue containing all the MQTT reply messages from all Arduinos communicating to this service + */ + public static Map> getReplyMsgQueue() { + return replyMsgQueue; + } + + /** + * @return the queue containing all the MQTT controls received to be sent to any Arduinos connected to this server + */ + public static Map> getInternalControlsQueue() { + return internalControlsQueue; + } + + private boolean waitForServerStartup() { + while (!IoTServerStartupListener.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + /** + * @return the "ArduinoMQTTConnector" object of this ArduinoControllerService instance + */ + @SuppressWarnings("unused") + public ArduinoMQTTConnector getArduinoMQTTConnector() { + return arduinoMQTTConnector; + } + + /** + * @param arduinoMQTTConnector an object of type "ArduinoMQTTConnector" specific for this ArduinoControllerService + */ + @SuppressWarnings("unused") + public void setArduinoMQTTConnector(final ArduinoMQTTConnector arduinoMQTTConnector) { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + ArduinoControllerService.this.arduinoMQTTConnector = arduinoMQTTConnector; + if (MqttConfig.getInstance().isEnabled()) { + arduinoMQTTConnector.connect(); + } else { + log.warn("MQTT disabled in 'devicemgt-config.xml'. Hence, ArduinoMQTTConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + @Path("controller/register/device/{deviceId}/{ip}/{port}") + @POST + public String registerDeviceIP(@PathParam("deviceId") String deviceId, @PathParam("ip") String deviceIP, + @PathParam("port") String devicePort, @Context HttpServletResponse response, + @Context HttpServletRequest request) { + String result; + if (log.isDebugEnabled()) { + log.debug("Got register call from IP: " + deviceIP + " for Device ID: " + deviceId + " of owner: "); + } + String deviceHttpEndpoint = deviceIP + ":" + devicePort; + deviceToIpMap.put(deviceId, deviceHttpEndpoint); + result = "Device-IP Registered"; + response.setStatus(Response.Status.OK.getStatusCode()); + if (log.isDebugEnabled()) { + log.debug(result); + } + return result; + } + + @Path("controller/device/{deviceId}/bulb") + @POST + @Feature(code = "bulb", name = "Control Bulb", type = "operation", description = "Control Bulb on Arduino Uno") + public void switchBulb(@PathParam("deviceId") String deviceId, @QueryParam("protocol") String protocol, + @FormParam("state") String state, @Context HttpServletResponse response) { + + LinkedList deviceControlList = internalControlsQueue.get(deviceId); + String operation = "BULB:" + state.toUpperCase(); + log.info(operation); + if (deviceControlList == null) { + deviceControlList = new LinkedList<>(); + deviceControlList.add(operation); + internalControlsQueue.put(deviceId, deviceControlList); + } else { + deviceControlList.add(operation); + } + response.setStatus(Response.Status.OK.getStatusCode()); + } + + @Path("controller/device/{deviceId}/temperature") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Feature( code="temperature", name="Temperature", type="monitor", description="Request temperature reading from Arduino agent") + public SensorRecord requestTemperature(@PathParam("deviceId") String deviceId, @QueryParam("protocol") String protocol, + @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + ArduinoConstants.SENSOR_TEMPERATURE); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + response.setStatus(Response.Status.OK.getStatusCode()); + return sensorRecord; + } + + @Path("controller/sensor") + @POST + @Consumes(MediaType.APPLICATION_JSON) + public void pushData(DeviceData dataMsg, @Context HttpServletResponse response) { + String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + String deviceId = dataMsg.deviceId; + float pinData = dataMsg.value; + SensorDataManager.getInstance().setSensorRecord(deviceId, ArduinoConstants.SENSOR_TEMPERATURE, + String.valueOf(pinData), + Calendar.getInstance().getTimeInMillis()); + if (!ArduinoServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.warn("An error occured whilst trying to publish pin data of Arduino with ID [" + + deviceId + "] of owner [" + owner + "]"); + } + } + + @Path("controller/device/{deviceId}/controls") + @GET + public String readControls(@PathParam("deviceId") String deviceId, @QueryParam("protocol") String protocol, + @Context HttpServletResponse response) { + String result; + LinkedList deviceControlList = internalControlsQueue.get(deviceId); + String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + if (deviceControlList == null) { + result = "No controls have been set for device " + deviceId + " of owner " + owner; + response.setStatus(HttpStatus.SC_NO_CONTENT); + } else { + try { + result = deviceControlList.remove(); + response.setStatus(HttpStatus.SC_ACCEPTED); + } catch (NoSuchElementException ex) { + result = "There are no more controls for device " + deviceId + " of owner " + owner; + response.setStatus(HttpStatus.SC_NO_CONTENT); + } + } + if (log.isDebugEnabled()) { + log.debug(result); + } + return result; + } + + @Path("controller/temperature") + @POST + @Consumes(MediaType.APPLICATION_JSON) + public void pushTemperatureData(final DeviceData dataMsg, @Context HttpServletResponse response, + @Context HttpServletRequest request) { + String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + String deviceId = dataMsg.deviceId; + float temperature = dataMsg.value; + SensorDataManager.getInstance().setSensorRecord(deviceId, ArduinoConstants.SENSOR_TEMPERATURE, + String.valueOf(temperature), + Calendar.getInstance().getTimeInMillis()); + if (!ArduinoServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.warn("An error occured whilst trying to publish temperature data of Arduino with ID [" + deviceId + + "] of owner [" + owner + "]"); + } + } + + /** + * Retreive Sensor data for the device type + */ + @Path("controller/stats/device/{deviceId}/sensors/temperature") + @GET + @Consumes("application/json") + @Produces("application/json") + public SensorData[] getArduinoTemperatureStats(@PathParam("deviceId") String deviceId, + @QueryParam("from") long from, + @QueryParam("to") long to) { + String fromDate = String.valueOf(from); + String toDate = String.valueOf(to); + List sensorDatas = new ArrayList<>(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + String query = "deviceId:" + deviceId + " AND deviceType:" + + ArduinoConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; + String sensorTableName = ArduinoConstants.TEMPERATURE_EVENT_TABLE; + try { + List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); + Collections.sort(records, new Comparator() { + @Override + public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { + long t1 = (Long) o1.getValue("time"); + long t2 = (Long) o2.getValue("time"); + if (t1 < t2) { + return -1; + } else if (t1 > t2) { + return 1; + } else { + return 0; + } + } + }); + for (AnalyticsDataRecord record : records) { + SensorData sensorData = new SensorData(); + sensorData.setTime((long) record.getValue("time")); + sensorData.setValue("" + (float) record.getValue(ArduinoConstants.SENSOR_TEMPERATURE)); + sensorDatas.add(sensorData); + } + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } catch (DeviceManagementAnalyticsException e) { + String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; + log.error(errorMsg); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } + } + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/DeviceData.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/DeviceData.java new file mode 100644 index 000000000..00de218bd --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/DeviceData.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceData { + @XmlElement(required = true) public String deviceId; + @XmlElement(required = true) public String reply; + @XmlElement public Long time; + @XmlElement public String key; + @XmlElement public float value; +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/SensorData.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/SensorData.java new file mode 100644 index 000000000..22a58f0f8 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/dto/SensorData.java @@ -0,0 +1,44 @@ +package org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +/** + * This stores sensor event data for the device type. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorData { + + @XmlElement public Long time; + @XmlElement public String key; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + @XmlElement public String value; + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/exception/ArduinoException.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/exception/ArduinoException.java new file mode 100644 index 000000000..82766a0db --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/exception/ArduinoException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.exception; + +public class ArduinoException extends Exception { + private static final long serialVersionUID = 118512086957330189L; + + public ArduinoException(String errorMessage) { + super(errorMessage); + } + + public ArduinoException(String errorMessage, Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/transport/ArduinoMQTTConnector.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/transport/ArduinoMQTTConnector.java new file mode 100644 index 000000000..246fb7903 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/transport/ArduinoMQTTConnector.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.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.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +import org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.ArduinoControllerService; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +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.LinkedList; +import java.util.UUID; + +public class ArduinoMQTTConnector extends MQTTTransportHandler { + private static Log log = LogFactory.getLog(ArduinoMQTTConnector.class); + private static final String subscribeTopic = "wso2/" + ArduinoConstants.DEVICE_TYPE + "/#"; + private static final String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5); + + private static final String MESSAGE_TO_SEND = "IN"; + private static final String MESSAGE_RECEIVED = "OUT"; + + private ArduinoMQTTConnector() { + super(iotServerSubscriber, ArduinoConstants.DEVICE_TYPE, + MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic); + } + + @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(); + } + + @Override + public void processIncomingMessage(MqttMessage message, String... messageParams) throws TransportHandlerException { + if(messageParams.length != 0) { + // owner and the deviceId are extracted from the MQTT topic to which the message was received. + // = [ServerName/Owner/DeviceType/DeviceId] + String topic = messageParams[0]; + String[] topicParams = topic.split("/"); + String deviceId = topicParams[3]; + + if (log.isDebugEnabled()) { + log.debug("Received MQTT message for: [DEVICE.ID-" + deviceId + "]"); + } + + int lastIndex = message.toString().lastIndexOf(":"); + String msgContext = message.toString().substring(lastIndex + 1); + + LinkedList deviceControlList; + LinkedList replyMessageList; + + if (msgContext.equals(MESSAGE_TO_SEND) || msgContext.equals(ArduinoConstants.STATE_ON) || msgContext.equals( + ArduinoConstants.STATE_OFF)) { + + if (log.isDebugEnabled()) { + log.debug("Received a control message: "); + log.debug("Control message topic: " + topic); + log.debug("Control message: " + message.toString()); + } + + synchronized (ArduinoControllerService.getInternalControlsQueue()) { + deviceControlList = ArduinoControllerService.getInternalControlsQueue().get(deviceId); + if (deviceControlList == null) { + ArduinoControllerService.getInternalControlsQueue() + .put(deviceId, deviceControlList = new LinkedList()); + } + } + deviceControlList.add(message.toString()); + + } else if (msgContext.equals(MESSAGE_RECEIVED)) { + + if (log.isDebugEnabled()) { + log.debug("Received reply from a device: "); + log.debug("Reply message topic: " + topic); + log.debug("Reply message: " + message.toString().substring(0, lastIndex)); + } + + synchronized (ArduinoControllerService.getReplyMsgQueue()) { + replyMessageList = ArduinoControllerService.getReplyMsgQueue().get(deviceId); + if (replyMessageList == null) { + ArduinoControllerService.getReplyMsgQueue() + .put(deviceId, replyMessageList = new LinkedList<>()); + } + } + replyMessageList.add(message.toString()); + } + } + } + + @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 + + " for device-type - " + ArduinoConstants.DEVICE_TYPE, e); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("MQTT-Terminator: Thread Sleep Interrupt Exception at device-type - " + + ArduinoConstants.DEVICE_TYPE, e1); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage() throws TransportHandlerException { + + } + + @Override + public void processIncomingMessage(MqttMessage message) throws TransportHandlerException { + + } + + @Override + public void publishDeviceData() throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(MqttMessage publishData) throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/util/ArduinoServiceUtils.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/util/ArduinoServiceUtils.java new file mode 100644 index 000000000..bdba9fef1 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/controller/service/impl/util/ArduinoServiceUtils.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.controller.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +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.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import javax.ws.rs.HttpMethod; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; + +public class ArduinoServiceUtils { + private static final Log log = LogFactory.getLog(ArduinoServiceUtils.class); + + //TODO; replace this tenant domain + private static final String SUPER_TENANT = "carbon.super"; + private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature"; + + public static String sendCommandViaHTTP(final String deviceHTTPEndpoint, String urlContext, + boolean fireAndForgot) throws DeviceManagementException { + + String responseMsg = ""; + String urlString = ArduinoConstants.URL_PREFIX + deviceHTTPEndpoint + urlContext; + + if (log.isDebugEnabled()) { + log.debug(urlString); + } + + if (!fireAndForgot) { + HttpURLConnection httpConnection = getHttpConnection(urlString); + + try { + httpConnection.setRequestMethod(HttpMethod.GET); + } catch (ProtocolException e) { + String errorMsg = + "Protocol specific error occurred when trying to set method to GET" + + " for:" + urlString; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + responseMsg = readResponseFromGetRequest(httpConnection); + + } else { + CloseableHttpAsyncClient httpclient = null; + try { + + httpclient = HttpAsyncClients.createDefault(); + httpclient.start(); + HttpGet request = new HttpGet(urlString); + final CountDownLatch latch = new CountDownLatch(1); + Future future = httpclient.execute( + request, new FutureCallback() { + @Override + public void completed(HttpResponse httpResponse) { + latch.countDown(); + } + + @Override + public void failed(Exception e) { + latch.countDown(); + } + + @Override + public void cancelled() { + latch.countDown(); + } + }); + + latch.await(); + + } catch (InterruptedException e) { + if (log.isDebugEnabled()) { + log.debug("Sync Interrupted"); + } + } finally { + try { + if (httpclient != null) { + httpclient.close(); + + } + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("Failed on close"); + } + } + } + } + + return responseMsg; + } + + /* --------------------------------------------------------------------------------------- + Utility methods relevant to creating and sending http requests + --------------------------------------------------------------------------------------- */ + + /* This methods creates and returns a http connection object */ + public static HttpURLConnection getHttpConnection(String urlString) throws DeviceManagementException { + URL connectionUrl = null; + HttpURLConnection httpConnection; + + try { + connectionUrl = new URL(urlString); + httpConnection = (HttpURLConnection) connectionUrl.openConnection(); + } catch (MalformedURLException e) { + String errorMsg = + "Error occured whilst trying to form HTTP-URL from string: " + urlString; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } catch (IOException e) { + String errorMsg = "Error occured whilst trying to open a connection to: " + + connectionUrl.toString(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + return httpConnection; + } + + /* This methods reads and returns the response from the connection */ + + public static String readResponseFromGetRequest(HttpURLConnection httpConnection) + throws DeviceManagementException { + BufferedReader bufferedReader; + try { + bufferedReader = new BufferedReader(new InputStreamReader( + httpConnection.getInputStream())); + } catch (IOException e) { + String errorMsg = + "There is an issue with connecting the reader to the input stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + String responseLine; + StringBuilder completeResponse = new StringBuilder(); + + try { + while ((responseLine = bufferedReader.readLine()) != null) { + completeResponse.append(responseLine); + } + } catch (IOException e) { + String errorMsg = + "Error occured whilst trying read from the connection stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + try { + bufferedReader.close(); + } catch (IOException e) { + log.error( + "Could not succesfully close the bufferedReader to the connection at: " + + httpConnection.getURL()); + } + + return completeResponse.toString(); + } + + public static boolean publishToDAS(String deviceId, float temperature) { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String owner = ctx.getUsername(); + Object metdaData[] = {owner, ArduinoConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; + Object payloadData[] = {temperature}; + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + if (deviceAnalyticsService != null) { + try { + deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData, + new Object[0], payloadData); + } catch (DataPublisherConfigurationException e) { + return false; + } + return true; + } + return false; + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/permissions.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..f2595154a --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,87 @@ + + + + + + + + + + Register Device + /login + /controller/register/device/{deviceId}/{ip}/{port} + POST + + + + get device bulb statjs + /login + /controller/device/{deviceId}/bulb + GET + + + + get device temperature + /login + /controller/device/{deviceId}/temperature + GET + + + + get device temperature + /login + /controller/device/{deviceId}/temperature + GET + + + + get device temperature + /login + /controller/sensor + POST + + + + get controls + /login + /controller/device/{deviceId}/controls + POST + + + + push temperature + /login + /controller/temperature + POST + + + + get temperature + /login + /controller/stats/device/{deviceId}/sensors/temperature + GET + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..291443c92 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..c62aa6100 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,62 @@ + + + Arduino + Arduino + + + CXFServlet + org.apache.cxf.transport.servlet.CXFServlet + 1 + + + + + CXFServlet + /* + + + + isAdminService + false + + + doAuthentication + false + + + isSharedWithAllTenants + true + + + providerTenantDomain + carbon.super + + + + managed-api-enabled + true + + + managed-api-owner + admin + + + managed-api-context-template + /arduino/{version} + + + managed-api-application + arduino + + + managed-api-isSecured + true + + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/pom.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/pom.xml new file mode 100644 index 000000000..9824474d5 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/pom.xml @@ -0,0 +1,180 @@ + + + + + + arduino-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl + war + WSO2 Carbon - IoT Server Arduino ManagerService API + WSO2 Carbon - Arduino ManagerService API Implementation + http://wso2.org + + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.arduino.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.jwt.client.extension + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.application.extension + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + arduino_mgt + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/ArduinoManagerService.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/ArduinoManagerService.java new file mode 100644 index 000000000..6d5969c58 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/ArduinoManagerService.java @@ -0,0 +1,274 @@ +/* + * 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.wso2.carbon.device.mgt.iot.arduino.manager.service.impl; + +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey; +import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +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.arduino.manager.service.impl.util.APIUtil; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +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 org.wso2.carbon.device.mgt.jwt.client.extension.JWTClient; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClientManager; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.user.api.UserStoreException; + +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.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class ArduinoManagerService { + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private static final String KEY_TYPE = "PRODUCTION"; + private static ApiApplicationKey apiApplicationKey; + + @Path("manager/device/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(ArduinoConstants.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()); + } + } + + @Path("manager/device/{device_id}") + @PUT + public boolean updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name, + @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(ArduinoConstants.DEVICE_TYPE); + try { + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(ArduinoConstants.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) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } + } + + @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(ArduinoConstants.DEVICE_TYPE); + try { + return APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } + } + + @Path("manager/devices") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Device[] getArduinoDevices() { + try { + List userDevices = APIUtil.getDeviceManagementService().getDevicesOfUser( + APIUtil.getAuthenticatedUser()); + ArrayList userDevicesforArduino = new ArrayList<>(); + for (Device device : userDevices) { + if (device.getType().equals(ArduinoConstants.DEVICE_TYPE) && + device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) { + userDevicesforArduino.add(device); + } + } + return userDevicesforArduino.toArray(new Device[]{}); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } + } + + @Path("manager/device/download") + @GET + @Produces("application/octet-stream") + public Response downloadSketch(@QueryParam("deviceName") String customDeviceName) { + try { + ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), customDeviceName); + Response.ResponseBuilder rb = Response.ok(zipFile.getZipFile()); + rb.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\""); + return rb.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 (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } + } + + @Path("manager/device/generate_link") + @GET + public Response generateSketchLink(@QueryParam("deviceName") String deviceName) { + try { + ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName); + Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId()); + return rb.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 (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } + } + + private ZipArchive createDownloadFile(String owner, String deviceName) + throws DeviceManagementException, JWTClientException, DeviceControllerException, APIManagerException, + UserStoreException { + if (owner == null) { + throw new IllegalArgumentException("Error on createDownloadFile() Owner is null!"); + } + //create new device id + String deviceId = shortUUID(); + String applicationUsername = + PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration() + .getAdminUserName(); + if (apiApplicationKey == null) { + APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); + String[] tags = {ArduinoConstants.DEVICE_TYPE}; + apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( + ArduinoConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); + } + JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + String scopes = "device_type_" + ArduinoConstants.DEVICE_TYPE + " device_" + deviceId; + AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), + apiApplicationKey.getConsumerSecret(), owner, + scopes); + //create token + String accessToken = accessTokenInfo.getAccess_token(); + String refreshToken = accessTokenInfo.getRefresh_token(); + //Register the device with CDMF + boolean 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.getTenantDomainOftheUser(), + ArduinoConstants.DEVICE_TYPE, deviceId, + deviceName, accessToken, refreshToken); + zipFile.setDeviceId(deviceId); + return zipFile; + } + + 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); + } + + private boolean register(String deviceId, String name) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(ArduinoConstants.DEVICE_TYPE); + try { + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return false; + } + 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(ArduinoConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); + device.setEnrolmentInfo(enrolmentInfo); + 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()); + return false; + } + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/util/APIUtil.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/util/APIUtil.java new file mode 100644 index 000000000..5ffe0198c --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/manager/service/impl/util/APIUtil.java @@ -0,0 +1,55 @@ +package org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +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 { + + private static Log log = LogFactory.getLog(APIUtil.class); + + 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 getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String tenantDomain = threadLocalCarbonContext.getTenantDomain(); + return tenantDomain; + } + + 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static APIManagementProviderService getAPIManagementProviderService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + APIManagementProviderService apiManagementProviderService = + (APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null); + if (apiManagementProviderService == null) { + String msg = "API management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return apiManagementProviderService; + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/permissions.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..5d829b850 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,59 @@ + + + + + + + + + + Get device + /device-mgt/user/devices/list + /manager/device/{device_id} + GET + + + + Remove device + /device-mgt/user/devices/remove + /manager/device/{device_id} + DELETE + + + + Download device + /device-mgt/user/devices/add + /manager/device/download + GET + + + + Update device + /device-mgt/user/devices/update + /manager/device/{device_id} + PUT + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..98bfb6d53 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..e2c67f55a --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,51 @@ + + + Arduino + Arduino + + + 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 + /arduino/{version} + + + managed-api-application + arduino + + + managed-api-isSecured + true + + diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/pom.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/pom.xml new file mode 100644 index 000000000..0c870b611 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/pom.xml @@ -0,0 +1,124 @@ + + + + + + + arduino-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.arduino.plugin.impl + bundle + WSO2 Carbon - IoT Server Arduino Management Plugin + WSO2 Carbon - Arduino Management/Control Plugin Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Arduino Impl Bundle + org.wso2.carbon.device.mgt.iot.arduino.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*;resolution:=optional, + javax.naming;resolution:=optional, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers;resolution:=optional, + javax.net;resolution:=optional, + javax.net.ssl;resolution:=optional, + org.w3c.dom;resolution:=optional, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + org.wso2.carbon.device.mgt.extensions.feature.mgt.*, + org.wso2.carbon.utils.* + + + + !org.wso2.carbon.device.mgt.iot.arduino.plugin.internal, + org.wso2.carbon.device.mgt.iot.arduino.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 + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.utils + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/constants/ArduinoConstants.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/constants/ArduinoConstants.java new file mode 100644 index 000000000..6a9350075 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/constants/ArduinoConstants.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.constants; + +public class ArduinoConstants { + public final static String DEVICE_TYPE = "arduino"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "ARDUINO_DEVICE_ID"; + public final static String STATE_ON = "ON"; + public final static String STATE_OFF = "OFF"; + + public static final String URL_PREFIX = "http://"; + public static final String BULB_CONTEXT = "/BULB/"; + public static final String SONAR_CONTEXT = "/HUMIDITY/"; + public static final String TEMPERATURE_CONTEXT = "/TEMPERATURE/"; + + //type of the sensor + public static final String SENSOR_TEMPERATURE = "temperature"; + //sensor events summerized table name + public static final String TEMPERATURE_EVENT_TABLE = "DEVICE_TEMPERATURE_SUMMARY"; + public static final String DATA_SOURCE_NAME = "jdbc/ArduinoDM_DB"; + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/exception/ArduinoDeviceMgtPluginException.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/exception/ArduinoDeviceMgtPluginException.java new file mode 100644 index 000000000..93dc15683 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/exception/ArduinoDeviceMgtPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.exception; + + +public class ArduinoDeviceMgtPluginException extends Exception{ + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public ArduinoDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public ArduinoDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public ArduinoDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public ArduinoDeviceMgtPluginException() { + super(); + } + + public ArduinoDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManager.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManager.java new file mode 100644 index 000000000..5c7174d96 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManager.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 org.wso2.carbon.device.mgt.iot.arduino.plugin.exception.ArduinoDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.dao.ArduinoDAO; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.feature.ArduinoFeatureManager; +import java.util.List; + + +/** + * This represents the Arduino implementation of DeviceManagerService. + */ +public class ArduinoManager implements DeviceManager { + + private static final ArduinoDAO arduinoDAO = new ArduinoDAO(); + private static final Log log = LogFactory.getLog(ArduinoManager.class); + private ArduinoFeatureManager arduinoFeatureManager = new ArduinoFeatureManager(); + + @Override + public FeatureManager getFeatureManager() { + return arduinoFeatureManager; + } + + @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 Arduino device : " + device.getDeviceIdentifier()); + } + ArduinoDAO.beginTransaction(); + status = arduinoDAO.getDeviceDAO().addDevice(device); + ArduinoDAO.commitTransaction(); + } catch (ArduinoDeviceMgtPluginException e) { + try { + ArduinoDAO.rollbackTransaction(); + } catch (ArduinoDeviceMgtPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the Arduino 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 Arduino device enrollment data"); + } + ArduinoDAO.beginTransaction(); + status = arduinoDAO.getDeviceDAO().updateDevice(device); + ArduinoDAO.commitTransaction(); + } catch (ArduinoDeviceMgtPluginException e) { + try { + ArduinoDAO.rollbackTransaction(); + } catch (ArduinoDeviceMgtPluginException 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 Arduino 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 Arduino device : " + deviceId); + } + ArduinoDAO.beginTransaction(); + status = arduinoDAO.getDeviceDAO().deleteDevice(deviceId.getId()); + ArduinoDAO.commitTransaction(); + } catch (ArduinoDeviceMgtPluginException e) { + try { + ArduinoDAO.rollbackTransaction(); + } catch (ArduinoDeviceMgtPluginException 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 Arduino 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 Arduino device : " + deviceId.getId()); + } + Device iotDevice = arduinoDAO.getDeviceDAO().getDevice(deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (ArduinoDeviceMgtPluginException e) { + String msg = "Error while checking the enrollment status of Arduino 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 Arduino device : " + deviceId.getId()); + } + device = arduinoDAO.getDeviceDAO().getDevice(deviceId.getId()); + } catch (ArduinoDeviceMgtPluginException e) { + String msg = "Error while fetching the Arduino 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 Arduino device : " + deviceIdentifier); + } + ArduinoDAO.beginTransaction(); + status = arduinoDAO.getDeviceDAO().updateDevice(device); + ArduinoDAO.commitTransaction(); + } catch (ArduinoDeviceMgtPluginException e) { + try { + ArduinoDAO.rollbackTransaction(); + } catch (ArduinoDeviceMgtPluginException 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 Arduino 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 Arduino devices"); + } + devices = arduinoDAO.getDeviceDAO().getAllDevices(); + } catch (ArduinoDeviceMgtPluginException e) { + String msg = "Error while fetching all Arduino devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + +} \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManagerService.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManagerService.java new file mode 100644 index 000000000..15f1ff60c --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/ArduinoManagerService.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; + +import java.util.List; + +public class ArduinoManagerService implements DeviceManagementService { + private DeviceManager deviceManager; + + @Override + public String getType() { + return ArduinoConstants.DEVICE_TYPE; + } + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public void init() throws DeviceManagementException { + deviceManager=new ArduinoManager(); + + } + + @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/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/ArduinoDAO.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/ArduinoDAO.java new file mode 100644 index 000000000..133f0c74d --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/ArduinoDAO.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.exception.ArduinoDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.dao.impl.ArduinoDeviceDAOImpl; +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 ArduinoDAO { + + private static final Log log = LogFactory.getLog(ArduinoDAO.class); + static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal(); + + public ArduinoDAO() { + initArduinoDAO(); + } + + public static void initArduinoDAO() { + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(ArduinoConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + ArduinoConstants.DATA_SOURCE_NAME); + } + } + + public ArduinoDeviceDAOImpl getDeviceDAO() { + return new ArduinoDeviceDAOImpl(); + } + + public static void beginTransaction() throws ArduinoDeviceMgtPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new ArduinoDeviceMgtPluginException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws ArduinoDeviceMgtPluginException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new ArduinoDeviceMgtPluginException("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws ArduinoDeviceMgtPluginException { + 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 ArduinoDeviceMgtPluginException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws ArduinoDeviceMgtPluginException { + + 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 ArduinoDeviceMgtPluginException { + 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 ArduinoDeviceMgtPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/impl/ArduinoDeviceDAOImpl.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/impl/ArduinoDeviceDAOImpl.java new file mode 100644 index 000000000..1bb0f164f --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/dao/impl/ArduinoDeviceDAOImpl.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.exception.ArduinoDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.util.ArduinoUtils; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.dao.ArduinoDAO; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implements CRUD for arduino Devices. + */ +public class ArduinoDeviceDAOImpl { + + + private static final Log log = LogFactory.getLog(ArduinoDeviceDAOImpl.class); + + public Device getDevice(String deviceId) throws ArduinoDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + Device device = null; + ResultSet resultSet = null; + try { + conn = ArduinoDAO.getConnection(); + String selectDBQuery = + "SELECT ARDUINO_DEVICE_ID, DEVICE_NAME FROM ARDUINO_DEVICE WHERE ARDUINO_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, deviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + device = new Device(); + device.setName(resultSet.getString(ArduinoConstants.DEVICE_PLUGIN_DEVICE_NAME)); + if (log.isDebugEnabled()) { + log.debug("Arduino device " + deviceId + " data has been fetched from " + + "Arduino database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Arduino device : '" + deviceId + "'"; + log.error(msg, e); + throw new ArduinoDeviceMgtPluginException(msg, e); + } finally { + ArduinoUtils.cleanupResources(stmt, resultSet); + ArduinoDAO.closeConnection(); + } + return device; + } + + public boolean addDevice(Device iotDevice) throws ArduinoDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = ArduinoDAO.getConnection(); + String createDBQuery = + "INSERT INTO ARDUINO_DEVICE(ARDUINO_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, iotDevice.getDeviceIdentifier()); + stmt.setString(2,iotDevice.getName()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Arduino device " + iotDevice.getDeviceIdentifier() + " data has been" + + " added to the Arduino database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Arduino device '" + + iotDevice.getDeviceIdentifier() + "' to the Arduino db."; + log.error(msg, e); + throw new ArduinoDeviceMgtPluginException(msg, e); + } finally { + ArduinoUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device iotDevice) throws ArduinoDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = ArduinoDAO.getConnection(); + String updateDBQuery = + "UPDATE ARDUINO_DEVICE SET DEVICE_NAME = ? WHERE ARDUINO_DEVICE_ID = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, iotDevice.getName()); + stmt.setString(2, iotDevice.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Arduino device " + iotDevice.getDeviceIdentifier() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Arduino device '" + iotDevice.getDeviceIdentifier() + + "' data."; + log.error(msg, e); + throw new ArduinoDeviceMgtPluginException(msg, e); + } finally { + ArduinoUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteDevice(String iotDeviceId) throws ArduinoDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = ArduinoDAO.getConnection(); + String deleteDBQuery = + "DELETE FROM ARDUINO_DEVICE WHERE ARDUINO_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, iotDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Arduino device " + iotDeviceId + " data has deleted" + + " from the Arduino database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Arduino device " + iotDeviceId; + log.error(msg, e); + throw new ArduinoDeviceMgtPluginException(msg, e); + } finally { + ArduinoUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws ArduinoDeviceMgtPluginException { + + Connection conn = null; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device device; + List devices = new ArrayList(); + try { + conn = ArduinoDAO.getConnection(); + String selectDBQuery = + "SELECT ARDUINO_DEVICE_ID, DEVICE_NAME FROM ARDUINO_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + device = new Device(); + device.setDeviceIdentifier(resultSet.getString(ArduinoConstants.DEVICE_PLUGIN_DEVICE_ID)); + device.setName(resultSet.getString(ArduinoConstants.DEVICE_PLUGIN_DEVICE_NAME)); + } + if (log.isDebugEnabled()) { + log.debug("All Arduino device details have fetched from Arduino database."); + } + return devices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Arduino device data'"; + log.error(msg, e); + throw new ArduinoDeviceMgtPluginException(msg, e); + } finally { + ArduinoUtils.cleanupResources(stmt, resultSet); + ArduinoDAO.closeConnection(); + } + } + } \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/feature/ArduinoFeatureManager.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/feature/ArduinoFeatureManager.java new file mode 100644 index 000000000..d693f8e5b --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/feature/ArduinoFeatureManager.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl.feature; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; + +import java.util.List; + +public class ArduinoFeatureManager implements FeatureManager { + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + return false; + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + return false; + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeature(ArduinoConstants.DEVICE_TYPE, name); + } + + @Override + public List getFeatures() throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeatures(ArduinoConstants.DEVICE_TYPE); + } + + @Override + public boolean removeFeature(String name) throws DeviceManagementException { + return false; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + return false; + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/ArduinoUtils.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/ArduinoUtils.java new file mode 100644 index 000000000..f5e364274 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/ArduinoUtils.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.constants.ArduinoConstants; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.exception.ArduinoDeviceMgtPluginException; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +/** + * Contains utility methods used by Arduino plugin. + */ +public class ArduinoUtils { + + private static Log log = LogFactory.getLog(ArduinoUtils.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); + } + + /** + * Creates the device management schema. + */ + public static void setupDeviceManagementSchema() throws ArduinoDeviceMgtPluginException { + try { + Context ctx = new InitialContext(); + DataSource dataSource = (DataSource) ctx.lookup(ArduinoConstants.DATA_SOURCE_NAME); + DeviceSchemaInitializer initializer = + new DeviceSchemaInitializer(dataSource); + log.info("Initializing device management repository database schema"); + initializer.createRegistryDatabase(); + + } catch (NamingException e) { + log.error("Error while looking up the data source: " + ArduinoConstants.DATA_SOURCE_NAME); + } catch (Exception e) { + throw new ArduinoDeviceMgtPluginException("Error occurred while initializing Iot Device " + + "Management database schema", e); + } + } + + +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/DeviceSchemaInitializer.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/DeviceSchemaInitializer.java new file mode 100644 index 000000000..3567e776f --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/impl/util/DeviceSchemaInitializer.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.device.mgt.iot.arduino.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * Provides methods for initializing the database script. + */ +public class DeviceSchemaInitializer extends DatabaseCreator{ + + private static final Log log = LogFactory.getLog(DeviceSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + + File.separator + "cdm" + File.separator + "plugins" + File.separator; + + public DeviceSchemaInitializer(DataSource dataSource) { + super(dataSource); + } + + @Override + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptName); + } + return setupSQLScriptBaseLocation.replaceFirst("DBTYPE", databaseType) + scriptName; + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/internal/ArduinoManagementServiceComponent.java b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/internal/ArduinoManagementServiceComponent.java new file mode 100644 index 000000000..fc5fe40a3 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/arduino/plugin/internal/ArduinoManagementServiceComponent.java @@ -0,0 +1,86 @@ +/* + * 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.wso2.carbon.device.mgt.iot.arduino.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.exception.ArduinoDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.ArduinoManagerService; +import org.wso2.carbon.device.mgt.iot.arduino.plugin.impl.util.ArduinoUtils; +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.arduino.internal.ArduinoManagementServiceComponent" + * immediate="true" + */ +public class ArduinoManagementServiceComponent { + + private static final Log log = LogFactory.getLog(ArduinoManagementServiceComponent.class); + private ServiceRegistration arduinoServiceRegRef; + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Arduino Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + arduinoServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + new ArduinoManagerService(), null); + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug( + "-Dsetup is enabled. Iot Device management repository schema initialization is about " + + "to begin"); + } + try { + ArduinoUtils.setupDeviceManagementSchema(); + } catch (ArduinoDeviceMgtPluginException e) { + log.error("Exception occurred while initializing device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug("Arduino Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Arduino Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Arduino Device Management Service Component"); + } + try { + if (arduinoServiceRegRef != null) { + arduinoServiceRegRef.unregister(); + } + + if (log.isDebugEnabled()) { + log.debug( + "Arduino Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Arduino Device Management bundle", e); + } + } +} diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/pom.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/pom.xml new file mode 100644 index 000000000..950c0b438 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + arduino-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.arduino.ui + WSO2 Carbon - IoT Server Arduino UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/assembly/src.xml b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.hbs b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.hbs new file mode 100644 index 000000000..d4294f8d2 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.hbs @@ -0,0 +1,68 @@ +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "device-thumbnail"}} + +{{/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}} +
+
+
Operations Log
+
+ +
+
+ Not available yet +
+
+
+
+
+
+
+
+{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.js b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.js new file mode 100644 index 000000000..3198cf40f --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.js @@ -0,0 +1,44 @@ +/* + * 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"); + + 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") { + var viewModel = {}; + var deviceInfo = device.properties.DEVICE_INFO; + if (deviceInfo != undefined && String(deviceInfo.toString()).length > 0) { + deviceInfo = parse(stringify(deviceInfo)); + viewModel.system = device.properties.IMEI; + viewModel.machine = "Arduino"; + viewModel.vendor = device.properties.VENDOR; + } + device.viewModel = viewModel; + return {"device": device}; + } else { + response.sendError(404, "Device Id " + deviceId + "of type " + deviceType + " cannot be found!"); + exit(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.json b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/public/images/ardunio-icon.png b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.device-view/public/images/ardunio-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d478b0e303f60ccec7d7716e4609dfe8c757d66c GIT binary patch literal 21675 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 Qof+3u)l(@`dhzyu0YXp5wg3PC literal 0 HcmV?d00001 diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/ardunio-icon.png b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/ardunio-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d478b0e303f60ccec7d7716e4609dfe8c757d66c GIT binary patch literal 21675 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ⓈZTsFem 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/schematicsGuide.png b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/schematicsGuide.png new file mode 100644 index 0000000000000000000000000000000000000000..d2d1466abf58998743761cf716b632f56835aac1 GIT binary patch literal 94571 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/thumb.png b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..ad8170f33d34cf765cfb68e8adc370622d514b98 GIT binary patch literal 11936 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 Qof+3u)l(@`dhzyu0YXp5wg3PC literal 0 HcmV?d00001 diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/download.js b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/download.js new file mode 100644 index 000000000..0c22e5099 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/download.js @@ -0,0 +1,184 @@ +/* + * 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. + */ + +var modalPopup = ".wr-modalpopup"; +var modalPopupContainer = modalPopup + " .modalpopup-container"; +var modalPopupContent = modalPopup + " .modalpopup-content"; +var body = "body"; + +/* + * set popup maximum height function. + */ +function setPopupMaxHeight() { + $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30))); + $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2))); +} + +/* + * show popup function. + */ +function showPopup() { + $(modalPopup).show(); + setPopupMaxHeight(); + $('#downloadForm').validate({ + rules: { + deviceName: { + minlength: 4, + required: true + } + }, + highlight: function (element) { + $(element).closest('.control-group').removeClass('success').addClass('error'); + }, + success: function (element) { + $(element).closest('.control-group').removeClass('error').addClass('success'); + $('label[for=deviceName]').remove(); + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); +} + +/* + * hide popup function. + */ +function hidePopup() { + $('label[for=deviceName]').remove(); + $('.control-group').removeClass('success').removeClass('error'); + $(modalPopupContent).html(''); + $(modalPopup).hide(); +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + attachEvents(); +}); + +function attachEvents() { + /** + * Following click function would execute + * when a user clicks on "Download" link + * on Device Management page in WSO2 DC Console. + */ + $("a.download-link").click(function () { + var sketchType = $(this).data("sketchtype"); + var deviceType = $(this).data("devicetype"); + var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link"; + var payload = {"sketchType": sketchType, "deviceType": deviceType}; + $(modalPopupContent).html($('#download-device-modal-content').html()); + showPopup(); + var deviceName; + $("a#download-device-download-link").click(function () { + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + $('label[for=deviceName]').remove(); + if (deviceName && deviceName.length >= 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 deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/; + if (deviceName && deviceNameFormat.test(deviceName)) { + $('#downloadForm').submit(); + hidePopup(); + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + showPopup(); + setTimeout(function () { + hidePopup(); + }, 1000); + }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 == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showPopup(); + } else 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/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/jquery.validate.js b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.hbs b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.hbs new file mode 100644 index 000000000..1d34030f0 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.hbs @@ -0,0 +1,336 @@ +

+

Arduino

+
+
+ +
+ +
+ +
+ +
+ +
+

What it Does

+
+

Connect Arduino UNO board to WSO2 IoT Server and visualize sensor + data.

+
+

What You Need

+
+
    +
  • + ITEM 01 +    Arduino UNO Board. +
  • +
  • + ITEM 02 +    Adafruit Wifi Shield for Arduino. +
  • +
  • + ITEM 03 +    LED bulb connected to Pin 13. + (If not available, will use the one on the board.) +
  • +
  • + ITEM 04 +    Resister( e.g 330 ohms ) +
  • +
  • + STEP 05 +    Proceed to [Prepare] section. +
+
+ + View API + + + Download Sketch + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+ +

+
+ +
+

Prepare

+
+
    +
  • + 01 +    Wifi-Shield mounted onto the Arduino-UNO board +
  • +
  • + 02 +    Connect LED bulb to arduino as follows +

    + + + +
    +
  • + +
  • + 03 +    Download Arduino-Sketch from [Download Sketch] link above. +
  • +
  • + 04 +    Unzip the downloaded Arduino Agent +
  • +
  • + 05 +    Create a folder called "ArduinoBoardSketch" and move all source files + inside +
  • +
  • + 06 +    Open ArduinoBoardSketch.h and provide appropriate values for + [WLAN_SSID], + [WLAN_PASS], + [SERVICE_PORT], + [server] and + [deviceIP] + variables according to your network. +
  • +
  • + 07 +    Burn the sketch onto your Arduino board and let the program run. +
  • +
  • +                + + + + +    Arduino will publish it's internal temperature to WSO2-IoT-Server +

    +                + + + + +    LED on PIN 13 can be controlled from Device Management page. +
  • +
+
+
+ +
+
+

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 and monitor Real-Time data. +
  • +
  • + 03 +    You can also view analytics of the data published to IoT-Server by + navigating to Device Analytics page. +
  • +
+
+
+
+

Click on the image to zoom

+
+ + + +
+
+
+ +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + {{js "/js/jquery.validate.js"}} + +{{/zone}} +Status API Training Shop Blog About Pricing diff --git a/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.json b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/arduino-plugin/org.wso2.carbon.device.mgt.iot.arduino.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.arduino.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/arduino-plugin/pom.xml b/components/iot-plugins/arduino-plugin/pom.xml new file mode 100644 index 000000000..9e08a4120 --- /dev/null +++ b/components/iot-plugins/arduino-plugin/pom.xml @@ -0,0 +1,63 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.devicemgt-plugins + arduino-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.arduino.analytics + org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl + org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl + org.wso2.carbon.device.mgt.iot.arduino.plugin.impl + org.wso2.carbon.device.mgt.iot.arduino.ui + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml new file mode 100644 index 000000000..b1930e8f0 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml @@ -0,0 +1,261 @@ + + + + + + camera-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.camera.controller.service.impl + war + WSO2 Carbon - IoT Server Camera API + WSO2 Carbon - Camera Service Controller API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.camera.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2 + commons-codec + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + camera + + + + + + diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml new file mode 100644 index 000000000..98667f028 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml @@ -0,0 +1,261 @@ + + + + + + camera-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.camera.manager.service.impl + war + WSO2 Carbon - IoT Server Camera API + WSO2 Carbon - Camera Service Management API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.camera.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2 + commons-codec + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + camera_mgt + + + + + + diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml new file mode 100644 index 000000000..bd3c82af6 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml @@ -0,0 +1,123 @@ + + + + + + + camera-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.camera.plugin.impl + bundle + WSO2 Carbon - IoT Server Camera Management Plugin + WSO2 Carbon - Camera Management/Control Plugin Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Camera Impl Bundle + org.wso2.carbon.device.mgt.iot.camera.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*, + javax.naming, + javax.sql, + javax.xml.bind.annotation.*, + javax.xml.parsers, + javax.net, + javax.net.ssl, + org.w3c.dom, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + + + + !org.wso2.carbon.device.mgt.iot.camera.plugin.internal, + org.wso2.carbon.device.mgt.iot.camera.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/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java new file mode 100644 index 000000000..fa9b91d83 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.constants; + +public class CameraConstants { + public final static String DEVICE_TYPE = "camera"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "CAMERA_DEVICE_ID"; + public final static String STATE_ON = "ON"; + public final static String STATE_OFF = "OFF"; +} diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java new file mode 100644 index 000000000..1498a4b58 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 org.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.CameraDAO; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dto.IotDevice; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.util.IotDeviceManagementUtil; + +import java.util.ArrayList; +import java.util.List; + + +/** + * This represents the FireAlarm implementation of DeviceManagerService. + */ +public class CameraManager implements DeviceManager { + + private static final IotDeviceManagementDAOFactory iotDeviceManagementDAOFactory = new CameraDAO(); + private static final Log log = LogFactory.getLog(CameraManager.class); + + + @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; + IotDevice iotDevice = IotDeviceManagementUtil.convertToIotDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new Camera device : " + device.getDeviceIdentifier()); + } + CameraDAO.beginTransaction(); + status = iotDeviceManagementDAOFactory.getIotDeviceDAO().addIotDevice( + iotDevice); + CameraDAO.commitTransaction(); + } catch (IotDeviceManagementDAOException e) { + try { + CameraDAO.rollbackTransaction(); + } catch (IotDeviceManagementDAOException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the Camera device : " + device.getDeviceIdentifier(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public boolean modifyEnrollment(Device device) throws DeviceManagementException { + boolean status; + IotDevice iotDevice = IotDeviceManagementUtil.convertToIotDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug("Modifying the Camera device enrollment data"); + } + CameraDAO.beginTransaction(); + status = iotDeviceManagementDAOFactory.getIotDeviceDAO() + .updateIotDevice(iotDevice); + CameraDAO.commitTransaction(); + } catch (IotDeviceManagementDAOException e) { + try { + CameraDAO.rollbackTransaction(); + } catch (IotDeviceManagementDAOException 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 Camera 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 Camera device : " + deviceId); + } + CameraDAO.beginTransaction(); + status = iotDeviceManagementDAOFactory.getIotDeviceDAO() + .deleteIotDevice(deviceId.getId()); + CameraDAO.commitTransaction(); + } catch (IotDeviceManagementDAOException e) { + try { + CameraDAO.rollbackTransaction(); + } catch (IotDeviceManagementDAOException 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 Camera 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 Camera device : " + deviceId.getId()); + } + IotDevice iotDevice = + iotDeviceManagementDAOFactory.getIotDeviceDAO().getIotDevice( + deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (IotDeviceManagementDAOException e) { + String msg = "Error while checking the enrollment status of Camera 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 Camera device : " + deviceId.getId()); + } + IotDevice iotDevice = iotDeviceManagementDAOFactory.getIotDeviceDAO(). + getIotDevice(deviceId.getId()); + device = IotDeviceManagementUtil.convertToDevice(iotDevice); + } catch (IotDeviceManagementDAOException e) { + String msg = "Error while fetching the Camera 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; + IotDevice iotDevice = IotDeviceManagementUtil.convertToIotDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug( + "updating the details of Camera device : " + deviceIdentifier); + } + CameraDAO.beginTransaction(); + status = iotDeviceManagementDAOFactory.getIotDeviceDAO() + .updateIotDevice(iotDevice); + CameraDAO.commitTransaction(); + } catch (IotDeviceManagementDAOException e) { + try { + CameraDAO.rollbackTransaction(); + } catch (IotDeviceManagementDAOException 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 Camera device : " + deviceIdentifier; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public List getAllDevices() throws DeviceManagementException { + List devices = null; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Camera devices"); + } + List iotDevices = + iotDeviceManagementDAOFactory.getIotDeviceDAO().getAllIotDevices(); + if (iotDevices != null) { + devices = new ArrayList(); + for (IotDevice iotDevice : iotDevices) { + devices.add(IotDeviceManagementUtil.convertToDevice(iotDevice)); + } + } + } catch (IotDeviceManagementDAOException e) { + String msg = "Error while fetching all Camera devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + +} \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java new file mode 100644 index 000000000..a6241b940 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.camera.plugin.constants.CameraConstants; + +import java.util.List; + +public class CameraManagerService implements DeviceManagementService{ + private DeviceManager deviceManager; + @Override + public String getType() { + return CameraConstants.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 CameraManager(); + } + + @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/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java new file mode 100644 index 000000000..35571d851 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.camera.plugin.constants.CameraConstants; +import org.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.impl.CameraDeviceDAOImpl; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceDAO; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOFactoryInterface; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class CameraDAO extends IotDeviceManagementDAOFactory implements IotDeviceManagementDAOFactoryInterface { + + private static final Log log = LogFactory.getLog(CameraDAO.class); + static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal(); + + public CameraDAO() { + initFireAlarmDAO(); + } + + public static void initFireAlarmDAO() { + dataSource = getDataSourceMap().get(CameraConstants.DEVICE_TYPE); + } + + @Override public IotDeviceDAO getIotDeviceDAO() { + return new CameraDeviceDAOImpl(); + } + + public static void beginTransaction() throws IotDeviceManagementDAOException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new IotDeviceManagementDAOException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws IotDeviceManagementDAOException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new IotDeviceManagementDAOException("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws IotDeviceManagementDAOException { + 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 IotDeviceManagementDAOException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws IotDeviceManagementDAOException { + + 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 IotDeviceManagementDAOException { + 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 IotDeviceManagementDAOException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java new file mode 100644 index 000000000..59e68335b --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.camera.plugin.constants.CameraConstants; +import org.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.CameraDAO; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceDAO; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.util.IotDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.iot.util.iotdevice.dto.IotDevice; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implements IotDeviceDAO for camera Devices. + */ +public class CameraDeviceDAOImpl implements IotDeviceDAO{ + + + private static final Log log = LogFactory.getLog(CameraDeviceDAOImpl.class); + + @Override + public IotDevice getIotDevice(String iotDeviceId) + throws IotDeviceManagementDAOException { + Connection conn = null; + PreparedStatement stmt = null; + IotDevice iotDevice = null; + ResultSet resultSet = null; + try { + conn = CameraDAO.getConnection(); + String selectDBQuery = + "SELECT CAMERA_DEVICE_ID, DEVICE_NAME" + + " FROM CAMERA_DEVICE WHERE CAMERA_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, iotDeviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + iotDevice = new IotDevice(); + iotDevice.setIotDeviceName(resultSet.getString( + CameraConstants.DEVICE_PLUGIN_DEVICE_NAME)); + Map propertyMap = new HashMap(); + + + + iotDevice.setDeviceProperties(propertyMap); + + if (log.isDebugEnabled()) { + log.debug("Camera device " + iotDeviceId + " data has been fetched from " + + "Camera database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Camera device : '" + iotDeviceId + "'"; + log.error(msg, e); + throw new IotDeviceManagementDAOException(msg, e); + } finally { + IotDeviceManagementDAOUtil.cleanupResources(stmt, resultSet); + CameraDAO.closeConnection(); + } + + return iotDevice; + } + + @Override + public boolean addIotDevice(IotDevice iotDevice) + throws IotDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = CameraDAO.getConnection(); + String createDBQuery = + "INSERT INTO CAMERA_DEVICE(CAMERA_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, iotDevice.getIotDeviceId()); + stmt.setString(2,iotDevice.getIotDeviceName()); + if (iotDevice.getDeviceProperties() == null) { + iotDevice.setDeviceProperties(new HashMap()); + } + + + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Camera device " + iotDevice.getIotDeviceId() + " data has been" + + " added to the Camere database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Camera device '" + + iotDevice.getIotDeviceId() + "' to the Camera db."; + log.error(msg, e); + throw new IotDeviceManagementDAOException(msg, e); + } finally { + IotDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean updateIotDevice(IotDevice iotDevice) + throws IotDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = CameraDAO.getConnection(); + String updateDBQuery = + "UPDATE CAMERA_DEVICE SET DEVICE_NAME = ? WHERE CAMERA_DEVICE_ID = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + + if (iotDevice.getDeviceProperties() == null) { + iotDevice.setDeviceProperties(new HashMap()); + } + stmt.setString(1, iotDevice.getIotDeviceName()); + + stmt.setString(2, iotDevice.getIotDeviceId()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Camera device " + iotDevice.getIotDeviceId() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Camera device '" + + iotDevice.getIotDeviceId() + "' data."; + log.error(msg, e); + throw new IotDeviceManagementDAOException(msg, e); + } finally { + IotDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteIotDevice(String iotDeviceId) + throws IotDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = CameraDAO.getConnection(); + String deleteDBQuery = + "DELETE FROM CAMERA_DEVICE WHERE CAMERA_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, iotDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Camera device " + iotDeviceId + " data has deleted from the Camera database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Camera device " + iotDeviceId; + log.error(msg, e); + throw new IotDeviceManagementDAOException(msg, e); + } finally { + IotDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public List getAllIotDevices() + throws IotDeviceManagementDAOException { + + Connection conn = null; + PreparedStatement stmt = null; + ResultSet resultSet = null; + IotDevice iotDevice; + List iotDevices = new ArrayList(); + + try { + conn = CameraDAO.getConnection(); + String selectDBQuery = + "SELECT CAMERA_DEVICE_ID, DEVICE_NAME " + + "FROM CAMERA_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + iotDevice = new IotDevice(); + iotDevice.setIotDeviceId(resultSet.getString(CameraConstants.DEVICE_PLUGIN_DEVICE_ID)); + iotDevice.setIotDeviceName(resultSet.getString(CameraConstants.DEVICE_PLUGIN_DEVICE_NAME)); + + Map propertyMap = new HashMap(); + + iotDevice.setDeviceProperties(propertyMap); + iotDevices.add(iotDevice); + } + if (log.isDebugEnabled()) { + log.debug("All Camera device details have fetched from Firealarm database."); + } + return iotDevices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Camera device data'"; + log.error(msg, e); + throw new IotDeviceManagementDAOException(msg, e); + } finally { + IotDeviceManagementDAOUtil.cleanupResources(stmt, resultSet); + CameraDAO.closeConnection(); + } + + } + + } \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java new file mode 100644 index 000000000..b47c6d84a --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Map; + +/** + * Contains utility methods used by FireAlarm plugin. + */ +public class VirtualFireAlarmUtils { + + private static Log log = LogFactory.getLog(VirtualFireAlarmUtils.class); + + public static String getDeviceProperty(Map deviceProperties, String property) { + + String deviceProperty = deviceProperties.get(property); + + if (deviceProperty == null) { + return ""; + } + + return deviceProperty; + } + + +} diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java new file mode 100644 index 000000000..3546dd987 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.camera.plugin.impl.CameraManagerService; +import org.wso2.carbon.device.mgt.iot.service.DeviceTypeService; + + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.camera.plugin.internal + * .CameraManagementServiceComponent" + * immediate="true" + * @scr.reference name="org.wso2.carbon.device.mgt.iot.service.DeviceTypeServiceImpl" + * interface="org.wso2.carbon.device.mgt.iot.service.DeviceTypeService" + * cardinality="1..1" + * policy="dynamic" + * bind="setDeviceTypeService" + * unbind="unsetDeviceTypeService" + */ +public class CameraManagementServiceComponent { + + private static final Log log = LogFactory.getLog(CameraManagementServiceComponent.class); + private ServiceRegistration firealarmServiceRegRef; + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Camera Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + firealarmServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + new CameraManagerService(), null); + + if (log.isDebugEnabled()) { + log.debug( + "Camera Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error( + "Error occurred while activating Camera Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Camera Device Management Service Component"); + } + try { + if (firealarmServiceRegRef != null) { + firealarmServiceRegRef.unregister(); + } + + if (log.isDebugEnabled()) { + log.debug( + "Camera Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error( + "Error occurred while de-activating Camera Device Management bundle", e); + } + } + + protected void setDeviceTypeService(DeviceTypeService deviceTypeService) { + /* This is to avoid this component getting initialized before the common registered */ + if (log.isDebugEnabled()) { + log.debug("Data source service set to mobile service component"); + } + } + + protected void unsetDeviceTypeService(DeviceTypeService deviceTypeService) { + //do nothing + } + + +} diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml new file mode 100644 index 000000000..89bc215a2 --- /dev/null +++ b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + camera-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.camera.ui + WSO2 Carbon - IoT Server Camera UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/pom.xml b/components/iot-plugins/camera-plugin/pom.xml new file mode 100644 index 000000000..ebeed88cc --- /dev/null +++ b/components/iot-plugins/camera-plugin/pom.xml @@ -0,0 +1,63 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.devicemgt-plugins + camera-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.camera.controller.service.impl + org.wso2.carbon.device.mgt.iot.camera.manager.service.impl + org.wso2.carbon.device.mgt.iot.camera.plugin.impl + org.wso2.carbon.device.mgt.iot.camera.ui + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/pom.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/pom.xml new file mode 100644 index 000000000..104e025e7 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/pom.xml @@ -0,0 +1,243 @@ + + + + + digital-display-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api + war + WSO2 Carbon - IoT Server DigitalDisplay API + WSO2 Carbon - Digital Display Service API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2 + commons-codec + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + digital_display + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/DigitalDisplayControllerService.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/DigitalDisplayControllerService.java new file mode 100644 index 000000000..dde096d50 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/DigitalDisplayControllerService.java @@ -0,0 +1,432 @@ +/* + * 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.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.exception.DigitalDisplayException; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.util.DigitalDisplayMQTTConnector; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; +import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; +import javax.servlet.http.HttpServletResponse; +import javax.websocket.server.PathParam; +import javax.ws.rs.FormParam; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; + + +@API(name = "digital_display", version = "1.0.0", context = "/digital_display", tags = {"digital_display"}) +@DeviceType(value = "digital_display") +public class DigitalDisplayControllerService { + + private static Log log = LogFactory.getLog(DigitalDisplayControllerService.class); + private static DigitalDisplayMQTTConnector digitalDisplayMQTTConnector; + + private boolean waitForServerStartup() { + while (!IoTServerStartupListener.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + public DigitalDisplayMQTTConnector getDigitalDisplayMQTTConnector() { + return DigitalDisplayControllerService.digitalDisplayMQTTConnector; + } + + public void setDigitalDisplayMQTTConnector(final + DigitalDisplayMQTTConnector digitalDisplayMQTTConnector) { + + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + DigitalDisplayControllerService.digitalDisplayMQTTConnector = digitalDisplayMQTTConnector; + if (MqttConfig.getInstance().isEnabled()) { + digitalDisplayMQTTConnector.connect(); + } else { + log.warn("MQTT disabled in 'devicemgt-config.xml'. " + + "Hence, DigitalDisplayMQTTConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + /** + * Restart the running browser in the given digital display. + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/restart-browser") + @POST + @Feature(code = "restart-browser", name = "Restart Browser", type = "operation", + description = "Restart Browser in Digital Display") + public void restartBrowser(@PathParam("deviceId") String deviceId, + @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.RESTART_BROWSER_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Terminate all running processes. If this execute we have to reboot digital display manually. + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/terminate-display") + @POST + @Feature(code = "terminate-display", name = "Terminate Display", type = "operation", + description = "Terminate all running process in Digital Display") + public void terminateDisplay(@PathParam("deviceId") String deviceId, @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.TERMINATE_DISPLAY_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + + } + + /** + * Reboot running digital display + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/restart-display") + @POST + @Feature(code = "restart-display", name = "Restart Display", type = "operation", + description = "Restart Digital Display") + public void restartDisplay(@PathParam("deviceId") String deviceId, + @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.RESTART_DISPLAY_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Search through the sequence and edit requested resource + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + * @param name name of page need to change + * @param attribute this can be path,time or type + * @param newValue page is used to replace path + */ + @Path("device/{deviceId}/edit-sequence") + @POST + @Feature(code = "edit-sequence", name = "Edit Sequence", type = "operation", + description = "Search through the sequence and edit requested resource in Digital Display") + public void editSequence(@PathParam("deviceId") String deviceId, @FormParam("name") String name, + @FormParam("attribute") String attribute, @FormParam("new-value") String newValue, + @HeaderParam("sessionId") String sessionId, @Context HttpServletResponse response) { + try { + String params = name + "|" + attribute + "|" + newValue; + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.EDIT_SEQUENCE_CONSTANT + "::", params); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + + } + + @Path("device/{deviceId}/upload-content") + @POST + @Feature(code = "upload-content", name = "Upload Content", type = "operation", + description = "Search through the sequence and edit requested resource in Digital Display") + public void uploadContent(@PathParam("deviceId") String deviceId, @FormParam("remote-path") String remotePath, + @FormParam("screen-name") String screenName, @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + String params = remotePath + "|" + screenName; + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.UPLOAD_CONTENT_CONSTANT + "::", + params); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Add new resource end to the existing sequence + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + * @param type type of new resource + * @param time new resource visible time + * @param path URL of the new resource + */ + @Path("device/{deviceId}/add-resource") + @POST + @Feature(code = "add-resource", name = "Add Resource", type = "operation", + description = "Add new resource end to the existing sequence in Digital Display") + public void addNewResource(@PathParam("deviceId") String deviceId, + @FormParam("type") String type, + @FormParam("time") String time, + @FormParam("path") String path, + @FormParam("name") String name, + @FormParam("position") String position, + @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + String params; + try { + if (position.isEmpty()) { + params = type + "|" + time + "|" + path + "|" + name; + } else { + params = type + "|" + time + "|" + path + "|" + name + + "|" + "after=" + position; + } + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.ADD_NEW_RESOURCE_CONSTANT + "::", params); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Delete a resource in sequence + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + * @param name name of the page no need to delete + */ + @Path("device/{deviceId}/remove-resource") + @POST + @Feature(code = "remove-resource", name = "Remove Resource", type = "operation", + description = "Delete a resource from sequence in Digital Display") + public void removeResource(@PathParam("deviceId") String deviceId, @FormParam("name") String name, + @HeaderParam("sessionId") String sessionId, @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.REMOVE_RESOURCE_CONSTANT + "::", name); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Restart HTTP in running display + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/restart-server") + @POST + @Feature(code = "restart-server", name = "Restart Server", type = "operation", + description = "Stop HTTP Server running in Digital Display") + public void restartServer(@PathParam("deviceId") String deviceId, @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.RESTART_SERVER_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Get screenshot of running display + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/screenshot") + @POST + @Feature(code = "screenshot", name = "Take Screenshot", type = "operation", + description = "Show current view in Digital Display") + public void showScreenshot(@PathParam("deviceId") String deviceId, + @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.SCREENSHOT_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Get statistics of running display + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/get-device-status") + @POST + @Feature(code = "get-device-status", name = "Get Device Statistics", type = "operation", + description = "Current status in Digital Display") + public void getDevicestatus(@PathParam("deviceId") String deviceId, @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.GET_DEVICE_STATUS_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Stop specific display + * + * @param deviceId id of the controlling digital display + * @param sessionId web socket id of the method invoke client + * @param response response type of the method + */ + @Path("device/{deviceId}/get-content-list") + @POST + @Feature(code = "get-content-list", name = "Get Content List", type = "operation", + description = "Content List in Digital Display") + public void getResources(@PathParam("deviceId") String deviceId, @HeaderParam("sessionId") String sessionId, + @Context HttpServletResponse response) { + try { + sendCommandViaMQTT(deviceId, sessionId + "::" + DigitalDisplayConstants.GET_CONTENTLIST_CONSTANT + "::", ""); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DigitalDisplayException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Send message via MQTT protocol + * + * @param deviceId id of the target digital display + * @param operation operation need to execute + * @param param parameters need to given operation + * @throws DeviceManagementException + * @throws DigitalDisplayException + */ + private void sendCommandViaMQTT(String deviceId, String operation, String param) + throws DeviceManagementException, DigitalDisplayException { + String topic = String.format(DigitalDisplayConstants.PUBLISH_TOPIC, deviceId); + String payload = operation + param; + try { + digitalDisplayMQTTConnector.publishToDigitalDisplay(topic, payload, 2, false); + } catch (TransportHandlerException e) { + String errorMessage = "Error publishing data to device with ID " + deviceId; + throw new DigitalDisplayException(errorMessage, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/dto/DeviceJSON.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/dto/DeviceJSON.java new file mode 100644 index 000000000..309a6cf9f --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/dto/DeviceJSON.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceJSON { + @XmlElement(required = true) public String owner; + @XmlElement(required = true) public String deviceId; + @XmlElement(required = true) public String reply; +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/exception/DigitalDisplayException.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/exception/DigitalDisplayException.java new file mode 100644 index 000000000..c80d9e61a --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/exception/DigitalDisplayException.java @@ -0,0 +1,44 @@ +package org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.exception; + +/** + * Created by nuwan on 12/2/15. + */ +public class DigitalDisplayException extends Exception { + + private static final long serialVersionUID = 2736466230451105441L; + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public DigitalDisplayException(String msg, DigitalDisplayException nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public DigitalDisplayException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public DigitalDisplayException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public DigitalDisplayException() { + super(); + } + + public DigitalDisplayException(Throwable cause) { + super(cause); + } + + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/model/ScreenShotModel.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/model/ScreenShotModel.java new file mode 100644 index 000000000..e20f6991a --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/model/ScreenShotModel.java @@ -0,0 +1,33 @@ +package org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.model; + +public class ScreenShotModel { + + private String[] screenShotData; + private int length; + + public ScreenShotModel(){ + + } + + public ScreenShotModel(String[] screenShotData , int length){ + this.screenShotData = screenShotData; + this.length = length; + } + + public void setScreenShotData(String[] screrenShotData){ + this.screenShotData = screenShotData; + } + + public void setLength(int length){ + this.length = length; + } + + public String[] getScreenShotData(){ + return this.screenShotData; + } + + public int getLength(){ + return this.length; + } + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/util/DigitalDisplayMQTTConnector.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/util/DigitalDisplayMQTTConnector.java new file mode 100644 index 000000000..b356640ca --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/util/DigitalDisplayMQTTConnector.java @@ -0,0 +1,185 @@ +package org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.util; + +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.json.JSONObject; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.model.ScreenShotModel; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.websocket.DigitalDisplayWebSocketServerEndPoint; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; +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.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ScheduledFuture; + +@SuppressWarnings("no JAX-WS annotation") +public class DigitalDisplayMQTTConnector extends MQTTTransportHandler { + + private static Log log = LogFactory.getLog(DigitalDisplayMQTTConnector.class); + private static final String MQTT_TOPIC_APPENDER = "wso2/iot"; + private static final String subscribeTopic = + MQTT_TOPIC_APPENDER + "/" + DigitalDisplayConstants.DEVICE_TYPE + "/+/digital_display_publisher"; + + private static String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5); + + private ScheduledFuture dataPushServiceHandler; + + private Map screenshots = new HashMap<>(); + + private DigitalDisplayMQTTConnector() { + super(iotServerSubscriber, DigitalDisplayConstants.DEVICE_TYPE, + MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic); + } + + @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(); + } + + @Override + public void processIncomingMessage(MqttMessage message, String... messageParams) { + String topic = messageParams[0]; + String[] topicParams = topic.split("/"); + String owner = topicParams[2]; + String deviceId = topicParams[4]; + String[] messageData = message.toString().split("::"); + + if (log.isDebugEnabled()) { + log.debug("Received MQTT message for: [OWNER-" + owner + "] & [DEVICE.ID-" + deviceId + "]"); + } + + String sessionId = messageData[0]; + if (messageData.length == 2) { + String responseMessage = messageData[1]; + DigitalDisplayWebSocketServerEndPoint.sendMessage(sessionId, new StringBuilder(responseMessage)); + } else if (messageData.length == 3) { + String response = messageData[2]; + JSONObject schreenShot = new JSONObject(response); + String picId = schreenShot.getString("pic_id"); + String data = schreenShot.getString("data"); + int pos = schreenShot.getInt("pos"); + int length = schreenShot.getInt("size"); + createScreenShot(sessionId, picId, pos, length, data); + } + } + + private void createScreenShot(String sessionId, String picId, int pos, int length, String data) { + + ScreenShotModel screenShotModel = screenshots.get(picId); + + if (screenShotModel == null) { + screenShotModel = new ScreenShotModel(); + screenShotModel.setScreenShotData(new String[length + 1]); + screenShotModel.setLength(0); + screenshots.put(picId, screenShotModel); + } + if (screenShotModel.getLength() <= length) { + screenShotModel.getScreenShotData()[pos] = data; + screenShotModel.setLength(screenShotModel.getLength() + 1); + if (screenShotModel.getLength() == (length + 1)) { + StringBuilder displayScreenShot = new StringBuilder("Screenshot||"); + for (String screenshot : screenShotModel.getScreenShotData()) { + displayScreenShot.append(screenshot); + } + screenshots.remove(picId); + DigitalDisplayWebSocketServerEndPoint.sendMessage(sessionId, displayScreenShot); + } + } + } + + public void publishToDigitalDisplay(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); + } + + @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/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/websocket/DigitalDisplayWebSocketServerEndPoint.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/websocket/DigitalDisplayWebSocketServerEndPoint.java new file mode 100644 index 000000000..5ac54331e --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/controller/api/websocket/DigitalDisplayWebSocketServerEndPoint.java @@ -0,0 +1,64 @@ +package org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api.websocket; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.inject.Singleton; +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.util.HashMap; +import java.util.Map; + +@ServerEndpoint(value = "/{sessionId}") +@Singleton +public class DigitalDisplayWebSocketServerEndPoint { + + private static Log log = LogFactory.getLog(DigitalDisplayWebSocketServerEndPoint.class); + private static Map clientSessions = new HashMap<>(); + + /** + * This method will be invoked when a client requests for a + * WebSocket connection. + * + * @param userSession the userSession which is opened. + */ + @OnOpen + public void onOpen(Session userSession, @PathParam("sessionId") String sessionId) { + clientSessions.put(sessionId, userSession); + } + + /** + * This method will be invoked when a client closes a WebSocket + * connection. + * + * @param userSession the userSession which is opened. + */ + @OnClose + public void onClose(Session userSession) { + clientSessions.values().remove(userSession); + + } + + @OnError + public void onError(Throwable t) { + log.error("Error occurred " + t); + } + + /** + * This method will be invoked when a message received from device + * to send client. + * + * @param sessionId the client of message to be sent. + * @param message the message sent by device to client + */ + public static void sendMessage(String sessionId, StringBuilder message) { + Session session = clientSessions.get(sessionId); + if (session != null) { + session.getAsyncRemote().sendText(message.toString()); + } else { + log.error("Client already disconnected."); + } + } + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..edb998126 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..c6fb5fe50 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,77 @@ + + + + Digital-Display-Agent-Webapp + + JAX-WS/JAX-RS MDM Android Endpoint + JAX-WS/JAX-RS Servlet + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + CXFServlet + /* + + + + isSharedWithAllTenants + true + + + providerTenantDomain + carbon.super + + + isAdminService + false + + + doAuthentication + true + + + + + managed-api-enabled + true + + + managed-api-owner + admin + + + managed-api-context-template + /digital_display/{version} + + + managed-api-application + digital_display + + + managed-api-isSecured + true + + + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/pom.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/pom.xml new file mode 100644 index 000000000..b68cd2afd --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/pom.xml @@ -0,0 +1,246 @@ + + + + + digital-display-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api + war + WSO2 Carbon - IoT Server DigitalDisplay API + WSO2 Carbon - Digital Display Service API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2 + commons-codec + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.jwt.client.extension + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.application.extension + provided + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + digital_display_mgt + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/DigitalDisplayManagerService.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/DigitalDisplayManagerService.java new file mode 100644 index 000000000..063a23d39 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/DigitalDisplayManagerService.java @@ -0,0 +1,243 @@ +/* + * 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.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey; +import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +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.digitaldisplay.manager.api.util.APIUtil; +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 org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClient; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClientManager; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.user.api.UserStoreException; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.*; +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.Date; +import java.util.UUID; + +public class DigitalDisplayManagerService { + + private static Log log = LogFactory.getLog(DigitalDisplayManagerService.class); + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private static final String KEY_TYPE = "PRODUCTION"; + private static ApiApplicationKey apiApplicationKey; + + @Path("manager/device") + @POST + public boolean register(@QueryParam("deviceId") String deviceId, @QueryParam("name") String name) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DigitalDisplayConstants.DEVICE_TYPE); + try { + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return false; + } + 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); + device.setName(name); + device.setType(DigitalDisplayConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); + device.setEnrolmentInfo(enrolmentInfo); + 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()); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DigitalDisplayConstants.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()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @PUT + public boolean updateDevice(@PathParam("device_id") String deviceId, + @QueryParam("name") String name, + @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DigitalDisplayConstants.DEVICE_TYPE); + try { + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(DigitalDisplayConstants.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; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @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(DigitalDisplayConstants.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; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @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 (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (IOException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType) + throws DeviceManagementException, JWTClientException, DeviceControllerException, APIManagerException, + UserStoreException { + if (owner == null) { + throw new IllegalArgumentException("Error on createDownloadFile() Owner is null!"); + } + //create new device id + String deviceId = shortUUID(); + if (apiApplicationKey == null) { + String applicationUsername = + PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration().getAdminUserName(); + APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); + String[] tags = {DigitalDisplayConstants.DEVICE_TYPE}; + apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( + DigitalDisplayConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); + } + JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + String scopes = "device_type_" + DigitalDisplayConstants.DEVICE_TYPE + " device_" + deviceId; + AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), + apiApplicationKey.getConsumerSecret(), owner, scopes); + //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.getTenantDomainOftheUser(), sketchType, deviceId, + deviceName, accessToken, refreshToken); + zipFile.setDeviceId(deviceId); + return zipFile; + } + + 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); + } + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/util/APIUtil.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/util/APIUtil.java new file mode 100644 index 000000000..a593b67cf --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/manager/api/util/APIUtil.java @@ -0,0 +1,54 @@ +package org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +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 { + + private static Log log = LogFactory.getLog(APIUtil.class); + + 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 getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String tenantDomain = threadLocalCarbonContext.getTenantDomain(); + return tenantDomain; + } + + 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static APIManagementProviderService getAPIManagementProviderService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + APIManagementProviderService apiManagementProviderService = + (APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null); + if (apiManagementProviderService == null) { + String msg = "API management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return apiManagementProviderService; + } +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/permissions.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..91ed83257 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,66 @@ + + + + + + + + + + Get device + /device-mgt/user/devices/list + /manager/device/{device_id} + GET + + + + Add device + /device-mgt/user/devices/add + /manager/device + POST + + + + Remove device + /device-mgt/user/devices/remove + /manager/device/{device_id} + DELETE + + + + Download device + /device-mgt/user/devices/add + /manager/device/{sketch_type}/download + GET + + + + Update device + /device-mgt/user/devices/update + /manager/device/{device_id} + POST + + + \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..14cc35426 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..e5ae03197 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,68 @@ + + + + Digital-Display-Agent-Webapp + + JAX-WS/JAX-RS MDM Android 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 + /digital_display/{version} + + + managed-api-application + digital_display + + + managed-api-isSecured + true + + + + diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/pom.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/pom.xml new file mode 100644 index 000000000..6cce70392 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/pom.xml @@ -0,0 +1,106 @@ + + + + + digital-display-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin + bundle + WSO2 Carbon - IoT Server DigitalDisplay Management Plugin + WSO2 Carbon - Digital Display Device-Type Plugin Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Impl Bundle + org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*;resolution:=optional, + javax.naming;resolution:=optional, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers;resolution:=optional, + javax.net, + javax.net.ssl, + org.w3c.dom, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + org.wso2.carbon.device.mgt.extensions.feature.mgt.*, + org.wso2.carbon.utils.* + + + !org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.internal, + org.wso2.carbon.device.mgt.iot.digitaldisplay.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 + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.utils + + + \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/constants/DigitalDisplayConstants.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/constants/DigitalDisplayConstants.java new file mode 100644 index 000000000..00ef15972 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/constants/DigitalDisplayConstants.java @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* Licensed 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants; + +public class DigitalDisplayConstants { + + public final static String DEVICE_TYPE = "digital_display"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "DIGITAL_DISPLAY_DEVICE_ID"; + public final static String RESTART_SERVER_CONSTANT = "restart_server"; + public final static String RESTART_DISPLAY_CONSTANT = "restart_display"; + public final static String RESTART_BROWSER_CONSTANT = "restart_browser"; + public final static String TERMINATE_DISPLAY_CONSTANT = "terminate_display"; + public final static String EDIT_SEQUENCE_CONSTANT = "edit_sequence"; + public final static String UPLOAD_CONTENT_CONSTANT = "upload_content"; + public final static String ADD_NEW_RESOURCE_CONSTANT = "add_new_resource"; + public final static String REMOVE_RESOURCE_CONSTANT = "remove_resources"; + public final static String SCREENSHOT_CONSTANT = "get_screenshot"; + public final static String GET_CONTENTLIST_CONSTANT = "get_content_list"; + public final static String GET_DEVICE_STATUS_CONSTANT = "get_device_status"; + public final static String PUBLISH_TOPIC = "wso2/iot/digital_display/%s/digital_display_subscriber"; + public static final String DATA_SOURCE_NAME = "jdbc/DigitalDisplayDM_DB"; +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/exception/DigitalDisplayDeviceMgtPluginException.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/exception/DigitalDisplayDeviceMgtPluginException.java new file mode 100644 index 000000000..6b184e57b --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/exception/DigitalDisplayDeviceMgtPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.exception; + + +public class DigitalDisplayDeviceMgtPluginException extends Exception{ + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public DigitalDisplayDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public DigitalDisplayDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public DigitalDisplayDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public DigitalDisplayDeviceMgtPluginException() { + super(); + } + + public DigitalDisplayDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManager.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManager.java new file mode 100644 index 000000000..f1e2befa3 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManager.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.*; +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 org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.exception.DigitalDisplayDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.dao.DigitalDisplayDAO; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.feature.DigitalDisplayFeatureManager; +import java.util.List; + + +/** + * This represents the DigitalDisplay implementation of DeviceManagerService. + */ +public class DigitalDisplayManager implements DeviceManager { + + private static final DigitalDisplayDAO digitalDisplayDAO = new DigitalDisplayDAO(); + private static final Log log = LogFactory.getLog(DigitalDisplayManager.class); + private FeatureManager featureManager = new DigitalDisplayFeatureManager(); + @Override + public FeatureManager getFeatureManager() { + return featureManager; + } + + @Override + public boolean saveConfiguration(TenantConfiguration tenantConfiguration) + throws DeviceManagementException { + return false; + } + + @Override + public TenantConfiguration getConfiguration() throws DeviceManagementException { + return null; + } + + @Override + public boolean enrollDevice(Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new DigitalDisplay device : " + device.getDeviceIdentifier()); + } + DigitalDisplayDAO.beginTransaction(); + status = digitalDisplayDAO.getDeviceDAO().addDevice(device); + DigitalDisplayDAO.commitTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException e) { + try { + DigitalDisplayDAO.rollbackTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the DigitalDisplay 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 DigitalDisplay device enrollment data"); + } + DigitalDisplayDAO.beginTransaction(); + status = digitalDisplayDAO.getDeviceDAO().updateDevice(device); + DigitalDisplayDAO.commitTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException e) { + try { + DigitalDisplayDAO.rollbackTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException 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 DigitalDisplay 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 DigitalDisplay device : " + deviceId); + } + DigitalDisplayDAO.beginTransaction(); + status = digitalDisplayDAO.getDeviceDAO().deleteDevice(deviceId.getId()); + DigitalDisplayDAO.commitTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException e) { + try { + DigitalDisplayDAO.rollbackTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException 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 DigitalDisplay 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 DigitalDisplay device : " + deviceId.getId()); + } + Device iotDevice = digitalDisplayDAO.getDeviceDAO().getDevice(deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (DigitalDisplayDeviceMgtPluginException e) { + String msg = "Error while checking the enrollment status of DigitalDisplay 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 DigitalDisplay device : " + deviceId.getId()); + } + device = digitalDisplayDAO.getDeviceDAO().getDevice(deviceId.getId()); + } catch (DigitalDisplayDeviceMgtPluginException e) { + String msg = "Error while fetching the DigitalDisplay 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 true; + } + + @Override + public boolean updateDeviceInfo(DeviceIdentifier deviceIdentifier, Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug( + "updating the details of DigitalDisplay device : " + deviceIdentifier); + } + DigitalDisplayDAO.beginTransaction(); + status = digitalDisplayDAO.getDeviceDAO().updateDevice(device); + DigitalDisplayDAO.commitTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException e) { + try { + DigitalDisplayDAO.rollbackTransaction(); + } catch (DigitalDisplayDeviceMgtPluginException 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 DigitalDisplay 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 DigitalDisplay devices"); + } + devices = digitalDisplayDAO.getDeviceDAO().getAllDevices(); + } catch (DigitalDisplayDeviceMgtPluginException e) { + String msg = "Error while fetching all DigitalDisplay devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManagerService.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManagerService.java new file mode 100644 index 000000000..429694b41 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/DigitalDisplayManagerService.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; + +import java.util.List; + +public class DigitalDisplayManagerService implements DeviceManagementService{ + private DeviceManager deviceManager; + @Override + public String getType() { + return DigitalDisplayConstants.DEVICE_TYPE; + } + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public void init() throws DeviceManagementException { + deviceManager= new DigitalDisplayManager(); + } + + @Override + public DeviceManager getDeviceManager() { + return deviceManager; + } + + @Override + public ApplicationManager getApplicationManager() { + return null; + } + + @Override + public void notifyOperationToDevices(Operation operation, List list) 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 list) throws ApplicationManagementException { + + } + + @Override + public void installApplicationForUsers(Operation operation, List list) throws ApplicationManagementException { + + } + + @Override + public void installApplicationForUserRoles(Operation operation, List list) throws ApplicationManagementException { + + } + +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/DigitalDisplayDAO.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/DigitalDisplayDAO.java new file mode 100644 index 000000000..01e9d702c --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/DigitalDisplayDAO.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.exception.DigitalDisplayDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.dao.impl.DigitalDisplayDeviceDAOImpl; + +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 DigitalDisplayDAO { + + private static final Log log = LogFactory.getLog(DigitalDisplayDAO.class); + static DataSource dataSource; // package local variable + private static ThreadLocal currentConnection = new ThreadLocal(); + + public DigitalDisplayDAO() { + initDigitalDisplayDAO(); + } + + public DigitalDisplayDeviceDAOImpl getDeviceDAO() { + return new DigitalDisplayDeviceDAOImpl(); + } + + public static void initDigitalDisplayDAO(){ + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(DigitalDisplayConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + DigitalDisplayConstants.DATA_SOURCE_NAME); + } + } + + public static void beginTransaction() throws DigitalDisplayDeviceMgtPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new DigitalDisplayDeviceMgtPluginException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws DigitalDisplayDeviceMgtPluginException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new DigitalDisplayDeviceMgtPluginException("Error occurred while retrieving data source connection", + e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws DigitalDisplayDeviceMgtPluginException { + 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 DigitalDisplayDeviceMgtPluginException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws DigitalDisplayDeviceMgtPluginException { + 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 DigitalDisplayDeviceMgtPluginException { + 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 DigitalDisplayDeviceMgtPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/impl/DigitalDisplayDeviceDAOImpl.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/impl/DigitalDisplayDeviceDAOImpl.java new file mode 100644 index 000000000..8df3567ff --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/dao/impl/DigitalDisplayDeviceDAOImpl.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.exception.DigitalDisplayDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.dao.DigitalDisplayDAO; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.util.DigitalDisplayUtils; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implements CRUD for digital display Devices. + */ +public class DigitalDisplayDeviceDAOImpl { + private static final Log log = LogFactory.getLog(DigitalDisplayDeviceDAOImpl.class); + + public Device getDevice(String iotDeviceId) throws DigitalDisplayDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + Device device = null; + ResultSet resultSet = null; + try { + conn = DigitalDisplayDAO.getConnection(); + String selectDBQuery = + "SELECT DIGITAL_DISPLAY_DEVICE_ID, DEVICE_NAME" + + " FROM DIGITAL_DISPLAY_DEVICE WHERE DIGITAL_DISPLAY_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, iotDeviceId); + resultSet = stmt.executeQuery(); + if (resultSet.next()) { + device = new Device(); + device.setName(resultSet.getString( + DigitalDisplayConstants.DEVICE_PLUGIN_DEVICE_NAME)); + if (log.isDebugEnabled()) { + log.debug("Digital Display device " + iotDeviceId + " data has been fetched from " + + "Digital Display database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Digital Display device : '" + iotDeviceId + "'"; + log.error(msg, e); + throw new DigitalDisplayDeviceMgtPluginException(msg, e); + } finally { + DigitalDisplayUtils.cleanupResources(stmt, resultSet); + DigitalDisplayDAO.closeConnection(); + } + return device; + } + + public boolean addDevice(Device device) throws DigitalDisplayDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DigitalDisplayDAO.getConnection(); + String createDBQuery = + "INSERT INTO DIGITAL_DISPLAY_DEVICE(DIGITAL_DISPLAY_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, device.getDeviceIdentifier()); + stmt.setString(2, device.getName()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Digital Display device " + device.getDeviceIdentifier() + " data has been" + + " added to the Digital Display database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Digital Display device '" + + device.getDeviceIdentifier() + "' to the Digital Display db."; + log.error(msg, e); + throw new DigitalDisplayDeviceMgtPluginException(msg, e); + } finally { + DigitalDisplayUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device device) throws DigitalDisplayDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DigitalDisplayDAO.getConnection(); + String updateDBQuery = + "UPDATE DIGITAL_DISPLAY_DEVICE SET DEVICE_NAME = ? WHERE DIGITAL_DISPLAY_DEVICE_ID = ?"; + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, device.getName()); + stmt.setString(2, device.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Digital Display device " + device.getDeviceIdentifier() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Digital Display device '" + + device.getDeviceIdentifier() + "' data."; + log.error(msg, e); + throw new DigitalDisplayDeviceMgtPluginException(msg, e); + } finally { + DigitalDisplayUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteDevice(String iotDeviceId) throws DigitalDisplayDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DigitalDisplayDAO.getConnection(); + String deleteDBQuery = + "DELETE FROM DIGITAL_DISPLAY_DEVICE WHERE DIGITAL_DISPLAY_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, iotDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Digital Display device " + iotDeviceId + " data has deleted" + + " from the Digital Display database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Digital Display device " + iotDeviceId; + log.error(msg, e); + throw new DigitalDisplayDeviceMgtPluginException(msg, e); + } finally { + DigitalDisplayUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws DigitalDisplayDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device iotDevice; + List iotDevices = new ArrayList(); + + try { + conn = DigitalDisplayDAO.getConnection(); + String selectDBQuery = + "SELECT DIGITAL_DISPLAY_DEVICE_ID, DEVICE_NAME FROM DIGITAL_DISPLAY_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + iotDevice = new Device(); + iotDevice.setDeviceIdentifier(resultSet.getString(DigitalDisplayConstants.DEVICE_PLUGIN_DEVICE_ID)); + iotDevice.setName(resultSet.getString(DigitalDisplayConstants.DEVICE_PLUGIN_DEVICE_NAME)); + iotDevices.add(iotDevice); + } + if (log.isDebugEnabled()) { + log.debug("All Digital Display device details have fetched from Digital Display database."); + } + return iotDevices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Digital Display device data'"; + log.error(msg, e); + throw new DigitalDisplayDeviceMgtPluginException(msg, e); + } finally { + DigitalDisplayUtils.cleanupResources(stmt, resultSet); + DigitalDisplayDAO.closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/feature/DigitalDisplayFeatureManager.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/feature/DigitalDisplayFeatureManager.java new file mode 100644 index 000000000..5ed07461a --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/feature/DigitalDisplayFeatureManager.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.feature; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; + +import java.util.List; + +public class DigitalDisplayFeatureManager implements FeatureManager { + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + return false; + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + return false; + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeature(DigitalDisplayConstants.DEVICE_TYPE, name); + } + + @Override + public List getFeatures() throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeatures(DigitalDisplayConstants.DEVICE_TYPE); + } + + @Override + public boolean removeFeature(String name) throws DeviceManagementException { + return false; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + return false; + } +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DeviceSchemaInitializer.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DeviceSchemaInitializer.java new file mode 100644 index 000000000..a527d26d7 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DeviceSchemaInitializer.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * Provides methods for initializing the database script. + */ +public class DeviceSchemaInitializer extends DatabaseCreator{ + + private static final Log log = LogFactory.getLog(DeviceSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + + File.separator + "cdm" + File.separator + "plugins" + File.separator; + + public DeviceSchemaInitializer(DataSource dataSource) { + super(dataSource); + } + + @Override + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptName); + } + return setupSQLScriptBaseLocation.replaceFirst("DBTYPE", databaseType) + scriptName; + } +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DigitalDisplayUtils.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DigitalDisplayUtils.java new file mode 100644 index 000000000..2e071d361 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/impl/util/DigitalDisplayUtils.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.constants.DigitalDisplayConstants; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.exception.DigitalDisplayDeviceMgtPluginException; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +/** + * Contains utility methods used by Digital Display plugin. + */ +public class DigitalDisplayUtils { + + private static Log log = LogFactory.getLog(DigitalDisplayUtils.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); + } + + /** + * Creates the device management schema. + */ + public static void setupDeviceManagementSchema() throws DigitalDisplayDeviceMgtPluginException { + try { + Context ctx = new InitialContext(); + DataSource dataSource = (DataSource) ctx.lookup(DigitalDisplayConstants.DATA_SOURCE_NAME); + DeviceSchemaInitializer initializer = + new DeviceSchemaInitializer(dataSource); + log.info("Initializing device management repository database schema"); + initializer.createRegistryDatabase(); + + } catch (NamingException e) { + log.error("Error while looking up the data source: " + DigitalDisplayConstants.DATA_SOURCE_NAME); + } catch (Exception e) { + throw new DigitalDisplayDeviceMgtPluginException("Error occurred while initializing Iot Device " + + "Management database schema", e); + } + } +} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/internal/DigitalDisplayManagementServiceComponent.java b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/internal/DigitalDisplayManagementServiceComponent.java new file mode 100644 index 000000000..52a6fdec8 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/digitaldisplay/plugin/internal/DigitalDisplayManagementServiceComponent.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.exception.DigitalDisplayDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.DigitalDisplayManagerService; +import org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.impl.util.DigitalDisplayUtils; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin.internal.DigitalDisplayManagementServiceComponent" + * immediate="true" + */ +public class DigitalDisplayManagementServiceComponent { + + private ServiceRegistration digitalDisplayServiceRegRef; + private static final Log log = LogFactory.getLog(DigitalDisplayManagementServiceComponent.class); + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Digital Display Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + digitalDisplayServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), new + DigitalDisplayManagerService(), null); + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug("-Dsetup is enabled. Iot Device management repository schema initialization is about " + + "to begin"); + } + try { + DigitalDisplayUtils.setupDeviceManagementSchema(); + } catch (DigitalDisplayDeviceMgtPluginException e) { + log.error("Exception occurred while initializing device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug("Digital Display Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Digital Display Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating DigitalDisplay Management Service Component"); + } + try { + if (digitalDisplayServiceRegRef != null) { + digitalDisplayServiceRegRef.unregister(); + } + if (log.isDebugEnabled()) { + log.debug("DigitalDisplay 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/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/pom.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/pom.xml new file mode 100644 index 000000000..ea1b8629a --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + digital-display-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.digitaldisplay.ui + WSO2 Carbon - IoT Server Digital Display UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/assembly/src.xml b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.hbs b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.hbs new file mode 100644 index 000000000..64d5eac67 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.hbs @@ -0,0 +1,98 @@ +{{#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"}} + +
+
+ +
+
+ +
+
+ Display Status +
+
+
+
Display View
+ + + +
+
+
Content List
+
    +
    +
    +
    Device Statistics
    +
      +
      +
      +
      + +
      +
      +
      Operations Log
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      +
      +{{/zone}} + +{{#zone "bottomJs"}} + + {{js "js/websocket.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.js b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.js new file mode 100644 index 000000000..9c203853b --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.js @@ -0,0 +1,40 @@ +/* + * 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") { + return {"device": device}; + } else { + response.sendError(404, "Device Id " + deviceId + "of type " + deviceType + " cannot be found!"); + exit(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.json b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/default-screen.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/default-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..df11c247a267953f023956b27f3122d3e7a0960c GIT binary patch literal 55235 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 z�|wN&J)_EA6Jbjp|;5O4K+c+UM3$H}#7wQ4GF{z=&Nq zvtSxl%Z2j&Z8obAjf1b>I##krsrT9uO@%ku82Y{2mf|uUq&QXe=Xz~-3r=aDT*i<0 z<*-YxfbgRQPfK(>yg@`2p63PAZXtR3OhO{q4FKE)7H{t(v_Wwy&77fbm08tD*l)HB z&o%Z8-|-R(q-7s;b=-jTxYXSCS2cReBn7zCrxRtLAM~#7`%isg7;fS&p9FfRJu
    • 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/thumb.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2a829c6f0a9fb2653eb552f6ab98ae230f2835 GIT binary patch literal 6246 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/js/websocket.js b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/js/websocket.js new file mode 100644 index 000000000..3075ba326 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.device-view/public/js/websocket.js @@ -0,0 +1,81 @@ +/* + * 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. + */ + +var displayClient = null; + +window.onload = function () { + connect(); +}; + +window.onbeforeunload = function () { + disconnect(); +} + +function connect() { + displayClient = new WebSocket("wss://" + host + ":" + port + "/digital_display/" + sessionId); + + displayClient.onmessage = function (event) { + var message = event.data; + var operationDiv = document.getElementById("div-operation-status"); + var type = message.split('||')[0]; + var reply = message.split('||')[1]; + + if (type.valueOf() == new String("Screenshot").valueOf()) { + document.getElementById('img').setAttribute('src', 'data:image/png;base64,' + reply); + document.getElementById('zoom-image').setAttribute('href', 'data:image/png;base64,' + reply); + } else if (type.valueOf() == new String("Success").valueOf()) { + $('#div-operation-status').removeClass('hidden'); + $('#div-operation-status').text(reply); + operationDiv.style.backgroundColor = '#DFF2BF'; + operationDiv.style.color = '#4F8A10'; + } else if (type.valueOf() == new String("Failed").valueOf()) { + $('#div-operation-status').removeClass('hidden'); + $('#div-operation-status').text(reply); + operationDiv.style.backgroundColor = '#FFBABA'; + operationDiv.style.color = '#D8000C'; + } else if (type.valueOf() == new String("ContentList").valueOf()) { + var resources = reply.split("-"); + var ul = document.getElementById("content-list"); + ul.innerHTML = ""; + for (i = 0; i < resources.length; i++) { + var li = document.createElement("li"); + li.appendChild(document.createTextNode(resources[i])); + ul.appendChild(li); + } + } else if (type.valueOf() == new String("DeviceStatus").valueOf()) { + var resources = reply.split("-"); + var ul = document.getElementById("device-statics"); + ul.innerHTML = ""; + for (i = 0; i < resources.length; i++) { + var li = document.createElement("li"); + li.appendChild(document.createTextNode(resources[i])); + ul.appendChild(li); + } + } + + setTimeout(function () { + $('#div-operation-status').addClass('hidden'); + }, 10000); + + }; + +} + +function disconnect() { + displayClient.close(); +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/display-icon.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/display-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..90342742a6d7275d137edec30c85c9a690c75d95 GIT binary patch literal 4963 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/myDevices_analytics.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/myDevices_analytics.png new file mode 100644 index 0000000000000000000000000000000000000000..8f55999a3cc67dc30ca686e871ae4a1f4f77ad17 GIT binary patch literal 195921 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%0AtQlWM#H2)$dBI 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�zNNR{>H;&s)`CHKstC>X?nd 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

      ISby2!A2}G`3*_anJE`angbv4riiuX{70{=m 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/add-resource.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/add-resource.png new file mode 100644 index 0000000000000000000000000000000000000000..d00ee206b189654aa0a146c4885c5580b75db92f GIT binary patch literal 4108 zcmaJ^dpJ~U`(87K#vtbqYK%c9j3I}S!#Eo|(oht(na1RhImF0mFh*jeB8QU1mMtPw zLI=z)B8Sb_R@uZzc5+NPjhw!*zuo?Re|-D5u4}FLeV*&N@8^D>_j%X47T3ewSqior z1^|E*-o=3+9NF79R807MZcXYE4k}DXAEqb$6f=qxP62EK=_e_0Je3qgAy7zxF=t*< zECE1dUx=3v)5qW`+3tqy+&F3A93Z zo46UeG3+V9Auh4u6wg?9FLLZ@GByxlV-2^Awh$6fDNGVPni@unu!y!o{K;z}oNv3) z2>72N%+pqg|A_K&^MKpa!zpkR15A{VJHrmh}ZDgo#h_x^= zwlFk;|8*gR*}?-)Sr8nY{>mk^tPsIWCc^@aj*5yhh%z>yhX+wr0;=lZvTHMmHKyd1d~AduipPj9N`tipr8qq2zq2VS-5ehG`CYREbPN6BqlxF zi%t*wUPX^!I+Gp|OlQFD?fi&sxbF;wHBA6r^nSyt)LI`;bLP7#9 z%pL4(ZL!97wirhv494+*t(mPc)(&IuWaMaOkFh)O9qT|RM^Y&?=67u1f3f!eh}~`o zDnpprff62amJ;X`PN%~ET)0KZ|IlLMXk>@Avo-ohzQ3@6|E$IKAF*hm81(k`{-5ps z?h^LU_Vn-O6&ioHKZPdj`EX%#t2>v>0DxpH-oe%@dT_>{8m8u~a`WKORr7n3*Z{Xm zpYUMr2~@gUh*tlxAQ4fGBW*0m5sjl~WuXZ<9VIq^`0+eJxePI7v%EiD&??Otv{P%7 z;}F7c=N;pS?X^8pd7v$iuw?AEbEcKs8`W+({rkeHriPKGq4=P)^dCdwqMF_uH0w3) zUBf&u=7v7(Byt@%ZNJRLFAs%mzCs&3?MuD~3l`73ANoMVCb%&W;|D+|B%&$Y zVg--`(nf_mT9{_2ZJg}E0T3lc3f9ev`uo#7ava&E!kXRWR zOC6C?dFJ5*LU1KyCWmi`wP;K$flijkUzL)aUFA^G-!grvdX zO!-4UJp!Z>f=w0A%OOn!cilLpVl5Bxnf;>;rsCIkf*r4y+=`FgpKf7mZ=9agEtZbx zy&)EW5??kY=)q7DeVPGD7D+kExcl*7$SX2wx{nG!O_$DD7CMEK7ZzL*~CB&em$ zi_XEy>@R~_S({-BrHLya_n2mG!iR<*QI~QPU;J?@NQpmwuJPHa3tJ>Q+TSO>DIA0P z!ehT(f@sgpUMz*9k`q5)8XB-VNUsFVy`{}PK6BK2b&I|m3Lu`&kAy6*ul|N=7vY`S zcR;B)v{|}XdU52rb;H`F>s6@~hEgJH4H@_Cox~kf@@=dL-vHN^BYkVVOD#GhRz=Jt z`n)`7O6FmIt*nw^1x%p)#0mE5-%Nj9|; zbA3NI%f6joR82HaD^ABfJ}SPki=%y1c`5a?Wrx$6^<6c=DOYa&PZuvjiZliS;V}4~ zw-y=;S8-E&H~ThR!2yS*_QcILzTb@;@@Q)BTi?fP412k?c{hM7DJa`r+!OpHP?hcq z3cQ@aESbU898ZR=FXrCP@dVYt46A>kkHo)kD8B=aRK(@5CJqShd2pJRSAhpFZ~1_Aax$UfgwN$>RFg@s$Z3g;`T=!_5ot zN%iD>%Uk%jzV<$cLCc;E^E!KDGA&>GHr56D<-92ze72`)dOB=%j51{~@>v(EkZoP+ zNEO7pPWEnXD6F-;=RXi0N+PS7^wxBFIJLReC~DaK&3T=}J+%Qv8}dIah5a-$wI||A zhdvY;Z#{gib2!3GS8&<#Tc8w6dE^8C{Xx{)lzvg*6S?7jSHqb$(ZF(No1YiS<7Qv| zm8(Y!8u-1PSMzl7nP2PxBT*j9n$o!=k*>aaHe$^{a&6tMh#2M9a`_5m4hAoae_4{K z_c1s!ZuHITK|ogg)$)ee49w7Fa;?JqE0cbdZm0X(P%rJ%pgW#pYX;6--4cmitf}DX zpH{R3%LTrJ;+Bh@)w-H`TEWL8@*%$(;KsM&6>OAW?frQ*K0O1dW~V{o!PAj2oawiF zw19#h%u4m=O&NS2Iu{VhOEsvwyZe=`jszES2?ED&J+-{~I{o}1Ubh(3W%Lu+D0Z>3 z0<4h<_e4uT13(rHA*Is;7yS?VwMai#&uj-yfTo7p{S@Ftx&B((Rap@TrF^z1KT)%9 zxzKXsdd*fs0RJWrl`*VKPi%*S5~(Lq*jWc)mm+vzVj;PXzA^8;DbmP(BR?}exwOs~ z!-26FoXqIZ!~&%tV+msWD7izH9sa8|jCwi`lBLOZ)eOk3H?ik*$l`o!k;3>}d}?Hiy|h=e(y0|?IU5Uw#>hEd zx=D;Ad)E6QcBtUO#7i<~HwfkJT?cll&(_$-mfyxaVu$9ALnFeN z``K-JUkK*vX6>!S!;t8hMVEU7RIg|5IZ|)1BGLIrjlCNSyg@wZ*wIl}Zk3kHjtVlU z;kd(;ijyGW&SG!K;z3z>fHqUaP^}i1FWcDjyXUVHnqL#g`p@Y8*nSas)JfphnWTv_ zUWw&m@9Jb?ingA3Z=s&As4Dx~R1N9OfAEy{J4EGQr%lhmsfzA{!DkC`UXlx&0R^jB z8NN!7w#@c)Glp~+k6AxEjNIS5zGkL>M2)j(b0zM^dNa2a!+Tq(H|4;#oNCMYojnO- zbi2Nry^6Nca{MNGGX@PY^dU4qJv8F-LGW<3rF9o8OnU!MQw=+Py}@Z}XJRQ|?&R!3 z>`x=-EAwo=petZz)Sj(j1>kJeV}eGZM%`}rH)-Uqt6Y=(%rF++yNej-xQ0<>3+mP*+a?CUU8hyj{Q zQAOE*G_FhE{XxR&rm8uq9Csuk=_4zYYZW~fbiV3Nxmd9L;CWb)-RN7xFc(l2Ds!+t z1*Yk9<e_7DmqwSRxXVVKMKyNA`Ot_ zeXH$dYrljK5H8DJrue1fn{@beZ=eRklPPG6Qv}=T$XydN;l1b@hlUMf9;4n+{2!w#S2V35i)Hbbp0*M zxj{?7(=pBAmn%V7!L4fAGiOQSpmNLk%Kf=aZd7dO+A*z!1AcO&Q3w#b;5du>FkO89 z0(k%7kE@eJOcrtd{Z|6MGwdf-ahamJJHPiwcZa;XT>q!Fw3 z-8XL59IogNC5OtHXGH&I>h~{sEEp;$c|r31b#iEy1{->Rm;-htep{QYr6W@S4kVrf zNuEX!+}W3;!}44qTx7>RvD-{dN5HpN#Sw>sU^W9!L)~R%&Hh zdrETFzaT?7$-)Oo;OH$pI*&dEsr~svwma>Y>n3&7IbzO}t0t}-DW|8pD`Zk>R2Gt* z0)_J$Rb~4g;oUi=b9?sfIV#~J4y;3VSnE8g$wjjFB7BUYt*{rlp=54-X*$wFOyDBJ z%fqNCVC)7f*R^r51eH(?@XK?8nTm);R)KRRDOG_*BmP!ZGXEvD9I-Ya%hNbL&|5<) ztJg@iaZ-QXeiNwg1|d7r-qww4D~f&^ICtiRlLMasDbKc*gxQV82Xr)?yP*Ub#pY){ z)yBoAd{Xj0A(MREI!^tyc5O`8gq@dDqc?axfDHnIo&hcpXiL`i|2f{#-J#l!$oV(w C`TxxT literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/edit-sequence.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/edit-sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..a194713b5e9ca7f3a92fffeb7a84f2a5b4ff3461 GIT binary patch literal 8099 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�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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/get-device-status.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/get-device-status.png new file mode 100644 index 0000000000000000000000000000000000000000..caf3f39ef350a4164d024d527adfdb54383556f4 GIT binary patch literal 3589 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

      1jK$^`2 zw_nj;Ac9%ph!77>1fbOPB02R5P7}Pqi2#IoNPrKeo+Ot5R0v@ax2F&TGWf{wlZw?}Rl|p2#Y-lD80S|5DwJixkrv*Zl?yozc1yes&G=Wgp2oXB+r?cP zz+`oR(PE2;$qWV~Uc(?xF>PV|F9hLW0L2d>e=CIjofiqCS>Pwv4~7{d^A+DSM*>i} znm$tF2jvies&xFFSF2;OaF`Pok4uwu&hNIJhPVG!p78&X(#_5cFxjMg4~Y;#uLpuH zO#&$rJ-A14B$zrZPtiSdBmm)hB*4c~PLM-@r}6M0&sGzt_rEE1+hTpn<)$rt| zV;B58Dcq8l4JM0n=MjxCAzusl-F46w40QN^WDve^(+C*dFJ1QUb0)yAkO2QJbMuUR*IK%M341XAdO$ z;Ok0w?voSkf14d?LeJM~myqlOZ+#^U&$TF0K7lg<2$WLxDeIS|65u{O{F--*ZyV); zMWfhUzP?}>zWe5G!Iw`k+fn(M+9^MZVL2xF<&;cC$|tBmfcudEzhV8dR02@I=N-IT zEM@rr%bqHDX7h33v(ah?dv;&#mEXz6jvS~!fH#l;i&?)cl>ij>btTW%x-15Ge|{dW zt=XEg_?^9QsM;gU^^Uy$s?YiH;Hi9q3IzB93BVkkC6xf=ZRyLiwG#@h!UJW&>H1b! z^w!tHXIpk5m~H&6{jR`U`2-aRP=N&K$NFVv0*LkYTcn)Bf{A^tFtylApPG z2y4o!g>}9?yO3uyx&?)we}8&~|O0+c`{0!%;x>|*(%6auKS2S6USmZ}o~j9GWKtU^^hea!6* zg`ibXen9z;focR`-V=~Q0967&Lw>K&o0woQf-`@hZeihq0|-Z}M4Ll$p%MX@14X3} zU>+X+%)6z5mL~8wu_Z^C>}i6#R}Zv>!vaxxDxaVd0p=qCm;!cmCqN3SfIk5yynJW| z4!x@80HnYNXjjeLdG}DhQ@}T0+CSB3wrte<=2GY$xJoJA^~2$tSiZ|lfU(c*nr?BX z|4r|kOQCxNTirK&b^rMFEZ=1&!04y9&$VUbN{%{BL3{Y!^*8SM@#TME`7Sd7Mn3V` ze0z4`YTiq*pH1c)TiOz6gWv9ULrYMf5-v9kvBUTRHZSF-<6hWN!FN?beidIs^@6g8 zu4XdWnYB6M@sDTQbNa2Jh+3Xl|L^>kb)G;N9{#jJZqWrUcx`45^k=M5^fPQLWfJoQ zc`1GMm2>tz@*SqMab^MxU%sgnM}Q3`E8i4tUIa)6=3%UTICw+lGc9*9P+-Kr$$w@T1GpVdf=lSwn~F0&wrfdhTrq zv^1j)P&@g+V^hCi`93=VmTf38J2MZVA;`7CN(qoG%FnSI;mz5(U^B5jQYtR>hcf;z zBKI}bQZB>L1ItPevwU9)0kVu%d%YuvIo5y)N(kWb1>vU~E8swF$Bh}2)d>cpwl#$A znUDsvO4v84?)>mHoOBz&Xy&`EO&e8Vzc>59vS|%0-Ic<_i(cyddnXR-b4(u(ULj z^&DvgShnG7dv4Jf9vL@L$R$8yYXELvxd+a9&i8(6dM;R8%=gX(RujMrr8!WX$-X*T zvFRwR-B$ySJ_EpL;+JAUISby}@;%u5$FiOyl>mRTq~|QKy7=`lB~t*UgWvn7{SXYd zfi)u!EKctEs@-DA73nZ_5PQ0K0}^-P>$}0%W&~%SZ*Xmk-_rnr=DO8LfSXv)kxGE2 zXa_9gX$L4Z0yiBz2TyNr61Ix9#?2#~@Vzn8uKT}RPQtr8D}uEP6`0A>6?~>C2rF

      T3CkF0HuQ+ zF#l4Aq_Q=!ptbqKYY)MeqY<~S*@4DiCST((Ca>ZaB)~gT&Xq%eK6t1wm@Ots&`>&$ zB_e>}KA*hzX?kYcQFZaXVYCoK63Uyv65@kS!2}bs@z@&aQp;DQZ z(Y4zdR_-W=SGS&Szd~f~&$0I-!CGt2Q1ueZQ0a>VsF8BMth+-J`~wfy@UUd#2@qBO zz6!Tcf@Q_rOX2c?{QM3+G!oCcL&6K9TJbYI02t97I5Sh;fTq1k0K_k>PJX`m!zIAmjJW`pmEJ?&n;3^j44Wh zM9PnXNbtn$p)ir-NT4QYsrSUjqr&vleh=7DsKfAt==!CPwCovx1gMny8?whcB!TdH zIHkFIM1Zc89|cVZKfZ1d%;Zp;Pc6`VOkTcMK0npL&QN37M-Z2O^zkE9zO2{DDIvgI zJP1Le_MCnoH&STzyqtu}r&UJK>%JiUdfu1;5InW%D136buEW1m zuculDykjZjQtEC*0x$)E#zP4KXkA1>2ZN~kCXqnSO%@xf6DpsUn4M+e4#{)E!_$U9 zNgrjU4V=@^tZc1+2qy?)`jaE?u&kw!>Ui*ydEms5fSkd>#dh?Yo#_M%a? z%s#lrl^!nUsq9$jG2XvGd_%{@}7|TP7w7+Sz+;+i6&{xB7ym zr2&_EqJb4TZMecMM@pyB?#-4()oPoFP%sAh|>*`tQ?1+U+^GZg+ye^OTM zAS8fW?(Zp{n2-eRuZgD-fJOo-h!UW?NFHH2!1Zo?xz;E$?Pi#Z_Q9-?eV}iqIxm-^ z8bu#`T?Om**MP^Lc*GT^Lz?qdDqclBpGE)?525lEy;hzF0caFB0^-}kZCM4lHe{ch zi2$rtGHrR%0|@y#52mCW8e5bOQ%Z7SQgId(AsOV_Uo_XAY4E}q#~a|&Bek&iY}Xx) zIsgTxs8zp!idR#WQW5mw5+%Jq`n(haNpKe)UJ?GFseoL>Cbk~nch^f=B9T(4g15h! ztnKbMd-Bt*FrqLGhUU9qK$aax2OH!#Es$n2x347pp)k08A*gE!2rrvBRo4oKYdlbf z#%Yb4A#uZC1d5iHV*@eYcL<06+V-KJ@B>u-t4e>D7Xe7yyHQ5d-&z!KB)fn@pu>!{ zh13H1L8#ZOG2cfaSp7Kt#k|8{FUokimVYd`X$VPhH6Cb>KM zypv%|Wagd7(dE71^hV3y7@R;Eiv(!mbq($mMiN|uhs`JvD-aDNfdm|L30Od*0xcQo zA%+5892xw~(**6@Q6Wl`#V(MS*7aIfCKEP#NcnB;!7Rk)Yf<^1@w|>IcZDQahKHr+ zuVMrWCD*&Ur$CBOP#787=)tx{R}lumT}x|s>g{^Jot(%@A>J{{CoD(hFXMeJwFp3l zAQdT^cK%BGj08Om33@(Z1Ii2}0G~Hu#y~ZyBME2;upOo3{MC>I*#(-~1U(7DoL^rR zuYB5Yn}o`*llik%%Ihwx%NNdm%lw7+pTe`7mghAA84O_L22z)7iFUF=hkp*LSnShrH>*3FOvdC67WnDM#L83MO-KhBY z^=xlaJWa9i1ih7XdY6qgTfpMT5GrdWo3Tj79qmE}TAMnJTZ{o!@?I>Zkb_!C3IaqS zrk+0sVtip&py`3$8!YV0Yg`jB3W`yr;hhp#x)|nTL2-N!NKN5Z6G=q?0u`jh!y_n^ zfXX!a)6_sjps9lP>(!bjgyB8tk8Clc!V@@fIs;jMl(_i|)&h=NA?XMZ1rlKhM7ES~ zMqv-QL*>&d!f3V$WH8cRK5g;RRxcwlgl%KmGNw0!;&4t%4+nh_E51!q)e%Z*dKV&F zxksg(s1=fy08tL#Vcv=y3#y1(JbWg+zuM#AC5Wmp%cJC>?r<7Ac+C8ca6yXad9o2|+dT zu7Ze*nF=OTqKeYmG8BPJi5L{^OfK84sPN-@-zzU%R0N0z5`ylp2qGf`3E2_kainlH z8=N;PeWFm<6?y1r{yrf}IVxPAH&AJSi<$r_bdMAPdO1=A=;cTepqC>>fL@OO2lwc5 U`2nA#D*ylh07*qoM6N<$f*Ve`>Hq)$ literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/restart-server.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/restart-server.png new file mode 100644 index 0000000000000000000000000000000000000000..eb947a87fb30cb8274b39b7d53df8cc70054c9e2 GIT binary patch literal 3293 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/screenshot.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5bca3d1aaed2a64396e3d759646f255fa17c56 GIT binary patch literal 8786 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 IM6N<$f^RDZD*ylh literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/terminate-display.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/operations/terminate-display.png new file mode 100755 index 0000000000000000000000000000000000000000..9919cfbb5a0ce9f1fe9f2007a75f41a59bacf804 GIT binary patch literal 4346 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/schematicsGuide.png b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/images/schematicsGuide.png new file mode 100644 index 0000000000000000000000000000000000000000..aec732f5f7b7fd3f8ab22907f0c2281a39bd22f4 GIT binary patch literal 393114 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 z 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

      f|M8Er3eiF`D@A1FvNPJrtc+}m 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�#}27l%|6Y-;OV`Bkg$k(u3B#!NI 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™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%0D}ZGKUZy zV(+sqlTRw4pLoGG^kuI2Xw32^71q7WC*>RSe1-fQQO;zf$IemUPEQoB>*<;ycp_{` zCVDx0ae6v$Wp8K&uM4eL4NnLe{esN@+@5_n7b37jkoU{78e>H`x`Za^==OhOa$hc> z=z`cn6EGJY_z;rM#AE%Ipq)&qJxi%ppmy!!*!@+EW(lZRmjH55AZXxtYPqSEmIQxW z)Il#sc&ppmWCFylt>h<4HEjI7n(M1N0srW*Am*Ul{=H(wfOgZi@uvU_J9OUo0#G;q zHS|oZJi5@Cs0z!LRF}5{A!k5zhdhDeYD}@!B7poo;47P8?;dylo$~9G_O_WMG7eeh zZ|LW<&`O)-jR^PLwkOj9?%$?%!Ux>gKhJ=@PPD$DtH!|L5=W4XpS)|d>v~VGE!ew{ zjcl;?PlCaU%Tv!YMExHJp1l&w1d|_Ikf>iw`cLFapC>#)@Fr2>q|9O}d83Fzt`0R+1#1%~F=@;HB9=LfU zXC8uzr)ZPX&Tro}kc*L)5~}g2LqoKK)Zu;g*-QWO&t~xHR=L=N@v0N-oOtuOy*a!r zIV?*4EXau8OTmnx?7pr&C@0>y_U%UG@)S?+_EnC1bj!79!@TywrI&Zz4MsPAkIcO7 zDql%y=QnLUb^oilHDS8(J!Pxp(&F^y`YJF({xtP3a*6-p?CSD~LpL6_Z;o{B?mIhr z<9o|*ek1%&f7lIYG={eLXQTfOwXd&kEWR_nH_coBe)falNanJ7q=JCvQCYF{QyEj% zE~~XRb1Mx>J2iLeSV)j4-8g0?gUxE%q1@TMKjLC z!t1y|<##c3!V%(}HBE1g>DSyYW zG-WJQ-nWW%vURaMZ=uwkP<}1G%*Cy2~ie&*EIE5Qv? zZKy>OPMyb~TRlAT8iDkgCLa?Mlc_b}(%!z+d!$UnGoc>{MU#A1iB#!^7jNe1-6& z(Q3K)vP#T(w1mfg0;W0(!ktxZ3fAP$>4c_KIYD?Bd=-UH)W+_nP} zODKkl$hWK%EQ_lolE#lzftwWE8EG@)f9kWp&CPwu%a~j)K|kx7kjF5Bi%xJcW7wW2<~1okJy(LT)R=T zWJC;>|2e+0FeLrp^p&!=-&eb$|Gu;>2lXe{b|1#QOo69A``1k2-l8AwQ8#`7(OXgN zM^|!!tA6oY+jT{!7maRgT!EjtNqh9x=IX}W-Obst_Nld{=*`^d4Z7)CdGx>ajY~^i zdC^O+b^nZ&yX#kv_NHss#Z7|W8dqoaPb!dw zT$+iC32E2rRZ>i1;_UMpRWcg5EOyDbPvdmkC)ZiFgh)*e=J$2#BA&*F15xEf63>3A zgn44QEzMTr`z(qHvU9WKFkhz3K>c`S0_Zn{;ZsBDZbn#>#9#uAf<2(-dd(2n2oEcD7H&v>my#HueIU@D|x$03-1y(Je4ZCkc z5Bt-mM6TOrD=;AJe#5oN#C$$>iLL$6EMNp`?eM8*Egz24i(tNtYng`0k1hC!g$F-= zs3Th7AsL!*nt3vMf>)H z24W=d>}A5pXc?wKPz@c&`A8snLoP@VfhdZAndqnj)FfZpo|Bp&o^WfatC zth*FzIU?-jzy8GL_(_TUD!$X8<*l-7owv;^4s0*=as%A2hUdP&B5j@RSmyPRZBfdv z@o1<@b-@HFpn1dyg5c###!t}@x-q@EvaB{CY-QnbmKON=DA>*OaW3e^Q#wK|uLV9L zIq2EJo<9Nnd>2v1;h=Uf9cl&aj}JeZe^dXfezhhs@64>soyTRRH5y-;PHe3v>=4_h zC^#M8+_qEbaAiBlqe_>fPK!W3tETxi;L)V+%HI zH(RO}&$|D4x%tJz?|5lCF|_`@eJR ztV@eG7Fe4%mrTN~qbH;8$7S|?5H;y*$uwPmp=-MIq0Mc^A$oZxZ;h+CbpyUft~5pu z&zRoWS{?Gg9`(E5v@dVjwN21otJY?yq_d7~21*#WHR<&HN9nj%C2MU^%WQ>;$|B@b zWnWPnwUxU`sm|WVLE8t!2<7kuO?|^<{ak;|WDsAZTIshpG-9ukkwZzP_90SyECM*W z;r3bd2~l`k5$wR8ncru<%fE{)Afq2?g)xUTmv4Wvzr&;gfc?jl!7fdFk`u7~GjT%b z@4)pN^|kVhiQguz&fLAohM0b9mId&|CNv_~<^XdgH6(*8Hro>!Z(%4DYf6d{gfpO!(iiojqt8NXMW%wgxlq2V2>3HFje~)cy z)scF{g}VOWOEI62*TgIu9n{!Nu|S^{87`t37`!J{C?T+(qP12jcM6FCt3 z0UlWcwp?$BlIN}&LoVZQt~lwWzM}3GV?^poUp@*TZ~aU3vN@+b0EyFi0E={6PbEDz z%%Fl{em@Z1fRV7a=GvO?s>0JNvV2Yf$Ege4<=)jv9Fp)neK2q__5rS7*kBBS05h0J zFygmPebxzZLZ({nzxU<>L)wR8u2@4^BEs=hNxI zFY@C+$XYxeH{JF$G}NV7?_X-^NikA^=Is}0>C*MW9>=kti5gGtjZeAe$20OV;{HM~ z58Oc3=j+6a8xNt+Rl!Gb~#1LXpF&NNgKon7a z_7mKy%W?~@;RAcEkmXvlI<_$D7Pd_==Nj)RJryZ~$!>%vc%v2$M@$b0HAPZxQzDJ= zv3D|`cClK;VyIptI7x(!i$*|8dL_AYG^(FDdD2xszWR!qM=}5BjRpDm!$!K5MSC8p zXLva!#er#<6W#_&Gvj4ur!}KTXI|bi_&2=zW#dL?3Y(?*mN2vQ9WYq0TVGgP`sBX(uki=mnclt? zy*@X+!Cq^dKWMuCSL)|d|MbS6!qwPzO6&o+{G;a<#$VyH#zZ2;%!wjFyQ7gWN4nM6 zkZ;e`tA%S}xoSEH$E$mBm3GcOsguXq-R1Yxkvw55Nd!j{BPxOSf2C(h&>S3C{#LQA zTaX5!ICZov4EtHY`1#h)7k5@-WTeIz`PP*ha_Z;(T1zVLt2Sug7fsGq; z&?fk;pGJYctTJRa9xRa0Jh4>E>a&&znuyDCIQJR;kD*8+8l}K}OsPagub$n2*8S57 zURKQK_T27^WlY($LxHS-lFzY4Ja0)Not(j_^M6dUq-eirS!}*1F*087YJ2YT2+9CT zQn!#Cj&*)NA!zIyGJ)#hOkJ&qt>vA?9+DLn_-wI#DVT@);V9>)!)iUv;IPfbhRRUT z*p;AxOHIHWg*lhsCg8luqY``|q68A8q|}O*@3NuVJ${2g+!P~Nn34N?7f^r$ovD>C zZ9DQ!KMAge${oF)&yyz*uU25xfl^<%y~__tv8G6$j`<=zebMWz0nX)I{_+7Ounw;` zrhophI$Dhe4jX}Wf+#kF&J;*f;5JSG<wq2IdCA@}zzq_*n(-^~{w3UX3*VVk}Z}1Wmym z(Eg?`=@FmS4E)4A4>-sA02O~}uJ9{Tc9I|iEHm1h)-dwr{4e(+7wuIB!=$y=&cCu> zxOX}1zKu3~C&t8pN4E)D1*@p{^lIL>m|$P7qbvIhyc16dz+nj(LV(!A;Jw!1ac`B& zC%#V=7Nq0lPb6hCsS%mAkO{Q4^4bK#3U>` zDfMI;fuI#KOz@5E{ zs}PN7enr0{d-7yloR-W;c!N8aw!IC-Zg}0gZK>Vq9l6Wa;mh)^VH4PfHgNbv#oS4;0$QFoaUA@Vbf~ zOIApvu3@%vPZ0sL-(S^=0N-~d5{W8=%A%1p5@H7;e%?pBDZr^<5T`&YOXd%?sFot$ zh&i6Z0uDsY{Uk+Z)6ezr60^XjIanU5BSW`K9b#K zNkWZ3^C!GZlx_6CQk#ehxOlwPKgC`CAhN0MIvyPC)Z_XNXMGqo|7$KpNzO0mi7mGU6H}F(N~w_skCmS2Hj;h18?0 zIdxfif<0VkQP$;q>D2cB2o1sI&BIie(%8=tXPjOIV~U7@0urD_AgeXiHtCMO-2Sp+ zQ22HkaB1$ykwJ*+kUg1kTm>xz>n=G#{Zf?!;#u>9@Z6xLA$7hfk3 zRE?9rg-fa>Y7r#4E}*=~Q83-g$0;C|@28n&QOx{PcH-R|w?X@!LzeRbwAA8phO$+r zU?YG&A#sm-mTo&}g=YdRub^XbC?u!Een_S91|+dk#So>ras5>R0ft10^m&6GGi|c# z7j->^HE&cy5^y=3Z+~%C3<2i4mTJ5|YY%qc7EM{12$4Wdx)6B8K4_=TfIW&$Wk4$b zBkdCVBe}#~N6RuWM-G+nXE|s7<2rlG#Rr4|r+`S}&mlp#+{NkOCxczAY_Bs#O$sC6 zn=0Lg0Nd_`Sd1AmzZFfefD}1pgGF3CNi4_|PX0ExHcoO5AmJ9kBJ%u#U;Z;tgQ(qD zq@(4?akDOSy=#fBWSl#=_OiF&ZgcqJQ;{RWmMFH)4w}$+zwLoms?b-@wi}7@abEA$ z1>X6GrOLnB*AUX69UevdOEsX2Y^`-VATSk2u^vn(!Xj5-WEhKSFiess=o5tRH3P}UYGlBn<1XEc zY{eZHP)vL@bwa$5?BY(#wYsl_;<$i4<>8+yV;mrOR0I-el@luUj^RXvy! z^60>KL@3t&&+&v{es`9xfEKN%of7LXGqJ5GWST_Yluqg>|on!-g+7}TpM=Ej+ZsI za3BWd$suCQ1WL8FpOej>1vo43cTxv5MTH!04Fi#sSvv}sD~h7pm>Gy%)FVs`k zB{kP`qs}}n?M!;p;5wRd{U~xULox=u$YJXrM%>~QKO`DTRM)eFEL@yLtho?H)+HT< zARs6dL0||EpKiqn>WCo^Lj^)dKE$sYUhv~!1T_R;Agy3?5++QGZmr#5BL-)*K4XT( zi;K(=O7Vjx4xWVgRJP{p)1VOHDwnFM9u?GXpg033qJ`~7if2($0~HT_t3zdd?fQlG zy~ucOZC#JQDV<-$UoK;cIxXka>nWh(P3^wQKOX`~NKf91 z4azHfcmOh&AlwH+^)>xfN-V`F_bs@}UaM?nI*OKpQ5E?n9vVN{Gr{{XKWas?^|lBE z2Mt4*k&DSub=F!v2cEpM-uFywct~3!{fM8J=(nY1SH4cChk?Oi z#hGiDSku{>CT^SSE%BswSQXBFcKz5t$(Ge$vuCk0mv6#)#a}qK|M%|Q>5Yxea?|zu zk@auqPQpyjv-LZd-O7abo ziOB~mO3t$ZcWhHu)-u#^_FOr^S)()qv!^V0cv3D;!b zurq2ggZo{=t(^m$;u&;Js^|XNfndNoSPUWXmRDk{ROCP^d1b?m&{B6rh|*n2_=`&S zM&%g>3BL3Ba$kBsxjCzR7T+*wo$oI-l~03;T!42 zg5X335+v?TenA~D-t9{I{d}P+e#GdWQ>JReouhV z`S)w?V0M8g>sw3?5cU!VFnB>1fZHI&xl;ywNz07=`sH8&T5jiL6(C3eR4wToMnVw= zMMH})UAcg2J_U(!zBmDa-EB@U#$^y#+BGB{GRp_`h2dnRUBLx4hXy(e8o*>_@m_Zy zKn}&G=BG*@mY~@6blX?s64lTmBDS$;4L`pjVLU2P2u>Pf?u_jtbooFw+nD8%mwp=N zD16>+cFVWV5Y#%aI^3N*kugOis>l{z^C8)e_y~8KQ%aBCol35;3EO2s<9oX%6>ryz zNztudIezxpZ~s8z-HDp)^!~T~(~FskYoAiwVSx@NTy5&M8;{-C2WO+UzJ~wG+x&EC z&bg&8=ikJssP$iMLw68MA1Ma$dbn&W=vBIAd|46ss%A%AY^v2s1MYt|k02F+ZiaS8 z*0~YE4~FS9trBg)f@Xr-Bgh=BmH$LARe(t!hC2R2l%2Sel1^F~1Rr8RXE4EE^Qh$c z0;^(PHj}YG{r6GSt6aNs3>-=yDn>W83WjM}`lkv`MFnv!kurX05AK@`NsmL0v!V_A zBTq{7lqI)D1}Y^CIqL+ejK4!qLK$5A{M7MS(M|-v2vMnXFV^Y^XP9jhH=O)<^3AVP zLk!4FQXMRrujgS<1!Fn(+yhyL{@L{OS5z*1ULdLC1>?R*m*@>ZaHbvDNx0l4|84=I zyOs~cHEZKR(L;WM`4|1wwW};j020FQ98OR?78)g7q%s&#SmP6vpK__~m5|y*XG^+` z(bZuhq)^F0U+cT(?~;lUxmRXhAmH!>7>?JBL+2|W_EVV)njXcgq6ohR^y7iF!8wiL z-yEwLUN_a+Wn0X7vkrZ!{3|Xa(2yuHyRt^RB`oR;H=7fzT`F7H#&$*ySk8=-Gc~_= zvzi=nfzJfJ#B3d;(1#t>u!2bY?D3}~YE1Hl`4M{Q9bqpoOzCe_JfA^G7{pgH3eYwR zWQ+Sj&iOknNL&lh)i0B1u2;~~*&l3t5<#E=N=zUXQ#MeB56Gu^?QV>%lY}=CfCj6u zjZ$>nnPFu^5f4RlE1-%&f^26n$5naY3O7)plx|@F>1c`|FdXT|jLBgmob=@q%w>|N zb&sGKCI+Fx-~vl<=f>Ha`tSOGpI$VsUJGyUPQyA$-mh>XH4H4=5xf*}p~FqyN_X8| zp|u{#QtFW}v!FYkK9ePvw&!PS|6<#XeWidZP|6xF`!iubp!Jk;3Yg#@wWB`QX7Q<% z$HAe_$!EJ>oL^X2fO|m#I78Cx46Pa$^ws6jk`o5Du;x9ogYzGv^ zu-f6O9iKO(pS5NZ88JP>TU+$f30=9_gc9ew4e5k5+^)$n7ium}xvt7<%_*A2U?Ek1 zO*MdPY@l^6FoN>W43c6JM^4 zMMeJoOv;0&E=~V)yQ3Jr^)oYi`ODng#^%}RznB019-6C{aWM%>R99CxZl5fsB{f{x z3H%X8Xo*W^0+A=%M$e^xr^L3(?yZXCJB}BJHP+-c-UXg&N-j=<@J1?1)P>c z?kgDi#bm6se?JP7Mq^#R`>2tJW%4(xyy7~H&&Y77!pQKhD*GNl294$6vGo)rJLppn zjlwTiQaiMOkxWH4`%6gOXA2jGIzneF*dl58Q=|8j;9}q^RgD943Vjr;F=OIhx;@-! zd(=DM09_G;pV>Hu`*1Rs9Wl$yJfIqmg*|S^c?!W&?NS{-FrBh$>cPsEkP@Z|qO}s1 ztZKv|T)*|fhnV0m$$grCwZO;IiJ&uz`2rqKORs7LY67voi1z&K0tF7ORb#%U1Mc%M zJKxRO=+Y`3mS&(>5lS(Adb11C%Mg=9W@^n&dM>~NZHY6N`oIs!H~M*(gxNcj_7^Ya zj$_6NEqpwa^G1?fkGf3kO*Ojc1fdS1b7{y;`7A}~X6AbyqC|eKRz&oAkJ^Jetz^W#+}qb!d8r$#xk_6O?RerAilV}s@`1|z`4pIf)~hg#|e#?HUk zQT2OTj{CJP>;3umTI|#m*Mt9p{tPj87x#BhHtPF6nhIO%K#>N^uh()(Pg>bVk302% zRdk#YMDe5oz>*K0PvHhxgsf%Ct11lBr8z1NE^&Clj0Q2GTJMw?&v=6KknW5cIOEtN zI|UN07e%hYfeDf=kA*!W9>69rotiDWZnduUNKkO%456y!RrNNNa%oXmAmiW{bs#N4 zug5c<;nYEsI|mPD=#-Y1_q5WaVKedznj5o=YzLoOv&H#ZdK0>ysjbCo;%b&lJV5tX zI7g$@IM1ZU9(4$}Ng!0u(a;s^bQE?Oz?8B|;6|;9WD?yvv|U-(?xET!b>cmV2-L2e z>)=qF#^vzRP8|*4NF`HixSOef7OaS3e=()elTnLyjHJIBY^F)l;ppH?U-Q#cx@JfV z60FEsWGs%+Oq+5!+ws}K?O~-d>ph63yScm_&CU-CNGqZR9knZ}5n9cRez)a`J#jWL zFS9N53W!XnLx&>}pj!vRMS&aCP- z;bx>#SMAS+w;UmJMMhRjM9|){8i-a5k&F@($#N$evN*51xzCDth8xH$88ft8P7aA^ zcQFB}I3@lH8B!)Jq6B1yffp0_$FN!g-(bgs89rpNKYJ`=T>FqG9&5U!HpNE!xqhp6 zW4SL8h%0bu>1TYfp_(f&m?xI}ly`QN^8Q@RmKi_4^Fsc(UL0DDUlkI8FWH}(VuJ^M z{M@_?53VP}$6`iH-{TXi5sq#~3=zGCS+#RO8kM=>*ia;pSJwBb5!f*=Sd|JtyRHla zW9}PEBufO)T!o)wUrblMVGa~SM_*>$Ourj zIYV(2!(39bJXTaL`CxXt`dq%PM{U$Ast1iUG&@2PEGl_c|Kl;O;-e&+kZ2|)|G!<;$u`6AzJaw@k^8n+J9gI(OI`RgcPc;08yB~|lzaVxYER!gFf;6F z{f*4q2E&F7kEH=`!kIKSX0Ee<^XTJD=f#Pj+N{f0%W9H6Iu=JkdnH%^V*&=*!d&={ zDA8KDMaC5Rj2QoQXf;x6E(M@Iq#&O9I@%xB$JR4lQw<;~DTj0`$(`q%2Lo7>JsY6U zIKdg7Flc4Vh+n6NS)9yCgQUmW98qPek}z7#>^aGF7c##c-?Uf%HO zbuAc`ZI*9?Gd(08y%fYGNkS zTK(n-AxL(B9nr?Z7k?HTukHQnMIbIM9h)HpYL(v~fIAiavLN*R%+@de@7Im#oVGQ| ziZ2$!w->Z{tr@66D+Y7IUN{2M(vAP$YxaW0t_}2RqWL(r&<>b6301F??Me(=g@)XFj}Z_B6;JafAEKdZ`ZJnU#cA8;nk$su6z8eUTI^c4v7X~f!~c)3KCpNj zh>e4HsSE3LZT!jgA##ws#uA2xjkWPveC*nIw|3IfQcky;k+54jjd&j_mAZ0nM6xB5 z(T(YiPkME|7F7?xyI0xrz~OQsuHG5uVCg8uGbvL1Q>%g+aP68^<;59g34Og}pYO*Y zrEN!!j*PTTY*%RhK?WcupQ0dqnM_s3FX-^it?|n(YouAc2v#G-`G3 zs`_y`L_pH>(JQR*f?0E(dcCkR-kN zK~W?vUD%E+Ydx=SQ3*O?d;or>cY)z_x*bS7Vs(vch7JQhBbDIa@UzXna0IXdyTM6C zAeTR5woi*UeDn2t(?iy1~OIadkgh3#%23Ul^Hi<=o-&wnOa0#`1?eZMtj42v->V#P{E)0OFrpL(!V7Z zskS$4XDD_jLVR;GzqTY$i8mkQ^7mU}dmK(LDE0drTh|%2ox<50av+;(N^IcYa9HL;3*+5B=GaFq&cW@L_Y zMLO!ic-&7k8z!SJzl1}{((=I75OhQ?8x%)lO}PlpxH@ALVaPtZHYi6qou(i3N z{A2b08_&eY{2z>nP+Ys-Aln*G49-*Qajb7DC%4bpca?xWrZO3s7B970tJub7L|d|% z2{6lC@A|?4T&lRS^&s~dGNOOEtI@iIkic1^aFbPg?8K-1$+K3LYu3?BETX72GO1(jOS{PvT`6ecdU`-l{D45 zIu`q#6nPf&%l_6+%(E>Vw3y5&H|ug&yl4q{Ksqx+u`5(MW($@Zc5Gb0gp>UE2H_$) zKSa$5#wQJn0m@5)bp@o06URf;aw)jppb@RSvT~*_9{czU0R;rn&{|y>GP9hoiRR2_ zN>9^;q?deeGsm%JFl9@u8;w7%6s+Nfwt+Af|52%uF`%ymO9VC{MfVFx!pw)fd^ex( z-LH4Z_qg*~1i^3BYr@ryZ~%%5$)GKkn)8`qxGA<&SmM-x_qF_;+sbd%CW=uj74AA) zqqkooy>leJD*wyu&+8os7g)UOkyZHK(r>t@GFgu^>gAv$Nr3owb9eo2YK|{fRrvt1idai*stY+R!dC7ZHFzym6Ak~he80Lq+s-DTWr2Dw zoehVr8;t~BGLQdZFrsoS6JVZgVN{XW{tNcz{Q7pxa9bc=$9@c~?*_8Iz)Sgf(y60x z9cifFKS7NFiIkqQhiVefk2^rPY!v^jdskpOP{%N z@idZ=@SC}}G^dM-<>bEk;PuRzN%u|I_-dn+iGUQSEZ_I@!%8LweWV=+wOR0f3v-eZ zoTLas3;3m;CUr`N$&^y=zOM$m;=?FIdD@So&|4l(|KZXd4!D3N01;tQO+`FaYNY15 z41aB)RnsCu56PYT(l{WibQ8mT6u_41(ejHR)=ldLJLlu7$wx(kgO2jcmsdLw@+vZ) z^)1PMiu$-7&n`Gk$(m}~Hd$q!Z>Rs9jZmjw9QSrritTO$e$5TpHKms=K52KdwOX)~ z0~kSm#Hn%)+}~EIsfeiGKa{gMhS}G=`7%LEr#$fa@*INtz6qga!qLn`GH6|uec9mW zRj<((c9wYPeErCE7`gZYg$Z~GGIS5VV6E)WptTqcFrV%UB9)Hf|Ffl z0%E?m#hmSgH&-B6+rA8J0IbiGZoV>H#4xRjRPCf*#*NfM$aYU?@sg;BIyU zr)mzE3r;hYLkpc28(CX6V+2|$x@z%75r$qu9^5dTdg4~ZV^ql(Omh^5xKXzv5&+A? z$%Fbk*`m#cwhRo^oz!Q7`POJZ#^g=jb#*bKrO$xpQ8n&i^mjc@3h_f4Yo={1&&~X} z#Fo2ZZu9dRfOpcBN$5)d8`=Q=cjzh-|RhmC$1IqSK7`?ZMCAs;cGii&|0f+B7T ze5VyT47UyxUNvGg!O4+lSt;+|f|h!5H3Bz@qU3`Yi>NW<*eG@{5)vG-Z5&B_s@2qN zRckL_Y(4ix7+(=Y4rdRphGa7{p7k-01&R0Q1H&x-{E_$lsHT!ga!x>5Fm<6G~E$QbmbKmSq9ZRUedMdC)^i& zXaZHfX{u@zMDx>UTQ9_i`5Nl|om+YWo=er!(0l+9dWD^jgT%{F1U{4bEC(zHRH~fo zeD(3w{)f>r*oi9>Aq*QhlFin?T!Ry_pTvPn{ibd%G62z55kA8Nrw0Gk?Ju6pK~53Y z3UX$*W2cfnzPddhvA%FK>SriU1N~Pk4Cm2Q`10$xipI^_S1)hhZkxNa!~R3N&Zf&rW%QFn4AHfd++RG~rPcJKD$fQI4zYTB8)x|3@=22zE0 zHa`DZ@59-ke617uR8T+-rqmVmy_VqB$PgQi=PZGV6jgv!iUpuV{Sa_pT9^_X?&?Jw z)suj>FT!bY;gp9g&`GH%o#1%(z&qj6U){<23_43fV8Fz*`9(D5wbv53lC9_@{UxBq zULu40Ox$VhoC;D^znS-?)xkks2J->Jt5`9m62;`PoyY?}W-uHlFEa z!STSKzp87i0&r3^vJdudM+91f{F>d=Z&XJZhr@$|t-;tME(u~v&5AfXlb-jA0RKC8 zSs$Ku24}i%p0rapszPrd&cmZ)OYcU&lsd`FsDAw zUA=I-cCdRPzrf(<&#jEw!h7pIJKM~~oxTT#Ydd$=d$y^NDTHBk0ez=!`++-O2XT8w z0cOP4+(;5}V z>$nxw*pN7@A)hw`gCJ~c zG4%k;ngX@N%*^;PkO|06Pxy=wu4F%^sWw-psT=8|pO#BkZL6o+-C}7bPPHW+7+Rk! zK7IqPdRgD8CS8z23y5I~2!uFh*@S{29g5RzkYL44^65zjd(DJN;dF`NIpp{HF1LC^ z^3Gku+Le551-a4M)=A*~b7yu~#r?#38V4+(I&(GT%ToJTz}k-42PoPg=3Wml4!$Og zhvH}qL`~5HTD92#h%(KvukJauZDsh9O=~&1_jlyp-#tdl&ZS$s(;x3`Zr#4{@zu_) zwR5WeSf@HBt>^b0!v~AA!598?Lt&4rd-M08nbjWa_Rb#d-XG$HsIUF{-=hl4Vu6O} z=R%yM9jH3|^W)A?4{bhbF&325Rwr_%&Iaa0~|!%p06|VnQDkpB&>s%*&O%i z#SGIGYP`NtLc<=*I=665JpZ7V#;H9HM?+nK;hPK_rtdhQne&j!1hDli>xqWIAgnI$ zi!mpt!3U!vV07H&VlwWgH-C{CRGkeHbf0eb&l&O516ZC>l(U~}mWK%az8blVH9{mmf#@83(6O*9(dPK^5{`aC#_M!hAh48H&EYZu0(E7q&<{m);SXRBUZo>CEC1c%!a!jd4++HEc62>-NdPDAe)+ zYFLWQkI9I&F{nNp5-*Am1HU+$)tpI#k7@%s?-*)p@AZ7+ZcQq58Kh$Azpi3gx2$)0<9bZ-UqBUxSzdCzt`& z8tX${3cNF5`=#T&HjYD^B*vvMgL{d2LMn(u(XPA=J2Mr&CgR&7 zYy`!#gSg3Q##}HMA9*>%f8i4$HX8Avpw`ItObuF;+A-l~GBfUEFBz|I*Ao7$8ruY= zf7d?l_axo@_1{|5*203z{!Dg+j#IEgs zA4n&zz1m%E8mYZJ7qzqXEoH=GVWW5F>fS%ny?+ag3mv5Wwf*&zhO5s+@BV!-QhVTI zM-+RSQ*3oQCZ_4W3P_G*}5aHqD@VAesrd{Rc_@u&Uv`V}(d$YEFK4jTGR#8y6m z*wD{LFNCZ0mEq1Zo6c+d(j(l41t^~)aNl^VbbNK~KFxqg-#m9Eekuq|fI06*y}i`@ z0htq?rk}+q_EoG9`{w(&W?;#N8K~SH(|F(44w8YIhE!QF#~W%8H%i!5}e27e0?&?4$N{d!q>_FtNg|BNB%x&u%2{uCy>vJL&3?SOR>$w`N z_eqbdh*Lzs0N*GNL-_K6>(`wa?ZQ_5bWj%-P_Gv(QWD zvD3`?*ileaJs`&l>j98=mCc;Yt!-AMvV?WVYItA=^@P-t=_aQwd9y3# z!V#)s^+NOOFVu?cq@~GSzK$k>@@bi9GjHs~YtWpiah?y%YiB&Q94WS&Dx=yNk2)yo zn5j7(<#aeptKj473l>dQe$Td1kYH_TWm2lR9&@~1Qa=)=&wPW1oiY*V4>{%V*ySRB zy>1oAt}W50f@BKpvZyBGiqWA21rai(yt2y7J-9DZ1h#5|1;lg-Sy9`ll#lg7igV33v2rer|xYGoZSCh{c(Rn zfSy?SD!h2;r6SY@yvs$Dz<6AQRFI&gWP6?*0U@|pab{Z`s?p$qTnaxWFt*vku6WSePxQqMj+A|dz z;*?a#Xq_HZ3%Vj){uswW6CTAN(SyxY+WWYiRrLxRL8geEAb(XATS{29ySj(|C0G{c z%WoI*0@e)k*Bq~nv_Pl=Eo$vTAc7fV=5Qz+)%ch?Ey7pRosZ&cr>%1YPr>d#k1;X+ zJ~L3ZW9@DL_R}NUY(>*EmeFK=Js^qAR4@ASMIA?{)4>`(7@%qT#UVAuHYjb?2$nvycth7_n!_41f1zZW6Dd_(~qJCwt_J5}=#!dw--28U+-@kH=txaZZ;r@?}!aMux6ZiJluGjVs^u(^s zbsF5cz0TU%Wu5#Dp$xaLMs2dT4e$La+~3sLTkPEVZ2Rid$i4MaXjx<1wzKWj)qg#O z`~Uv1qlRDZ6YlLoFH!9azkiNvK(}+o=9{a#{}OC9_I~V4)$RRZ_AbJkcwgiPS3l)b z#qr@;&-qpJ-;F|O8q7HxEz7f0}Brg52DITn$j(UzIv4j}bATllk;IDs%#OOU4Iy>*e?d=_V=$SMrG3%X&+?-o( zZ8B8EQu$fzyvuig?5;(mB)&Y0n%$OZJM1s6F^S4&O!nn9>F4ol{JO;sJF}yeggQL1 za@#|Jx2&0e)Qk5e7&-G_73|wnbsJZX*ql3m86P|L5AQD}b?&klE1DTE-A@j$taV1c zy0bKO@^9a%%I&^6`6eY&p&;EsxE}+JX`C$4mTQ5^#;z z6p0Ku;Yp+^IJaoB&}gz7mzyOK+iV`sU<_r9i+s%=M+yZF&;iSG9qKdpnp-Rpu*OgH zJhdDNh-UGv%G|uAzui~Ls&ut!eSv+1`cMGAGY-YIs_DlrH7dc3L zlUqxW=?01!P$XM1cp#B>-gv2sn{cLYNnH*kGLWOBoPir_bBm`p>W#t4YLu&=M_D-$ z+Gi|NrquA!Ltz}c>vI#UuFbG_;R&FyCr6P$@-$e_$cg>?k`yh$*98ai@|%2y1<4O# zO1vNMhP}GIvjw4LzHI(s-ut&%$Wzw~NNL>ts}S}~<8Jc3-%zh(yk%r3V=C$2PtlL0 zZT8B}d{*c08QcAP`TI~U}tYjbNg38!qn8^!li3kMOK0#4*onTeHpck*PE^g;6_|dA=#;GGkMy z7;&fKn-Zn%jmRVg1jLSTIeKmn9xPKE)uUrjixtcC?t+-f#+t{g-DOmiRs$*|sXE?B zi41QCJ^P0O>2g`YL}+Ur+L;o}Wi1CVEHd0;M7}?YbSW*`f^{Qj3fO^+%=A&dZ({wj z{BLiuY8!%Gli{vu#fB`4#Gk8eZ(*%yU0M*mJ)`Y=&hJ%ylD{1p4R(1ko*A&is;W&s!@-s_ z8h^IbKHizW^S5vJ^LbtL)!(-Jzb4i$yo|zK{cGkimc%=6Fd{xPF1KxXSWhq9`MX}* zY_1)_Sq4~J59H6w9>%9wS4J3H9(A#^nQFj&np0>}<v-crEzmZ(S758=50sYOjC&XcIUwmIW$ey2@~{Y#5eAKfS^|!2&;7(VFUNpxyF*xzbGaYp|ksQkWYW8nd*^!cU+ySfj{DL7N5GAhM<(PDe z@n|bQOvLZ3=6Jz(fq0*3c9ivvVf|i(B@xla%;uUWRi_q=7)rVRD@Cy=u4~W0)M>}f zN9?E2l2ORSKsBJBANFl|=2UL)y5fz)VY5tu?EaM{ytO)5!<@yz%A5`XYijEibha{RIMiyT1nG~H&|#vqp;ZW+cW8UsEYtEr!QNK&^}GK{ zul8gSKRP{TZ?w@i|4!TP4cz-kth?ITb}QxM?mF${?$@mSUwQj$qW276RlF2mPRGd zKOkjjZr8TY8D*nlyIW~rIyzoTNo}%g+N51_L(^`|l%G>Ejw#bXWyi=D>u%=XDn28C zsTCXBs$W)*V<5;#9U2xxcFIFY)vK2+F(Ks|!Wo6FID;-oC!CG84pB}AC}(cyZ-*p@ z-ymL5ccAHMzVKbveLosw^mhE4R&?Hwdk4S54D*;R(JQZaI!4{}VYbxP7%9oa&PWZp zGOoywW62rQ&BMdqjIe=Wz$2P;Onb=skOt}Tk!I%t^5l@-A8Ms5HPW&k7Es7Y> zdt1{;I`syypMo1%TB%f5I4oDKaHOu@1`kOkc(juq1Eod~hP&rWJX{lqW4ZC`l$&$n z1l2i%Be%?nQ{vE!4R@`*#lE;1!i{{a_sL#~=^I1qSJY=N7>w*@XCc2S6Nmefn`X-= zZ^A0%ehJ6Ow)=nY{oc8XlG=7( z{FcbMzkGdv_11H&zP)1B=*bH0Zc!`B|!V_n|VD~JvWj!5h%@ww2e!~r^m&R(M?dAkI0i>#4(5(iBl|aCPQPB>)=skb zmE``;{;&1Kb70Foygjoz>*1|T%&GEn;681&5f~V2j=hzW z`~1AlxwC$mVZ&_DX#$Lf@m4%{M~#OS52fsHO{^IjY|t)rFdzI__$*r3VUT(K?)HSO z;s1M$cmAB|yz}StVUM|!uOfG#Bj&fHdtdTecG>6WI=}V&p+N`3@{gS!ZwBuCWY2FN z-e=J+L~XF4dCJae*xbvUk9Ri@+`032X|XhH{pXv32U!O+4%eR9pw;bVf4#cL8o9gf z|L6U7-N0e*wAnf0)39*b$ZErr*J(?Ub&|uv8g+A&6xYz@D{N4hthw$3_jTK-lSbgwIqRTv||2n_k%9+u?zZ9LvbeE5z-$>bDCD zq5>I!A?8`$n8E9!F4Q9_g%*sa91gs>MZ>VZ( zNIU%;wXJ=5P;{iv;*8YIJoNx3bHK-T3)%JNm1) zHyhb}zr(iQ*{<#3`32m)NRt6H50`i8GJDxbxjX(?1~e*tI`gFD0}zxW>{xswH%}kd z)lLLl7#P7rml4DI$^t{|Dwaa-7x0vEwUZM@(kUYYA#rA-+j$EQ`J~M_S3{EKb&c6= zI*5Fv{rTh@{db!2p+={R-XL%2ia@3 z?(GvhJ2;-dkB@I&_H8_2Cia&HI@pw7_gHAT_nZB3H}>A|ZOHu%O%rAg-~BN&Fu%@X ztU-?0wY`B0ds~J3f0)~y+kf&_((0hj++NhkkWcQjuaRxTOUGKGInn|LlzP4TUet>S zrHQ4k;suM;kmBP&CE3-5!y*fF#Ew7N0mefCN-dS9E+yL_t+{9qh)E=e1N z+NL?_X1bP@$GEwIjI{!xr% zWd(Cny&Kvh2bStQbEAK4jv$&wkL0bOp>PD$`|hlTmZq@JtEz_>+cF!nMrw7v&`xj!-g< zeC}KypDY|oSsKT=6su7@UkDYZvyGm@6yFSMRJZh3)=j_3lFhf~~#R5Ipho=AF%0VqNUisWp$n&i(&d>hkJ3 zcYl6mN3Bm^{Zh=QIn(kQ~Q!0O?}Tz@&n(S!)-?e@xDyt=vEO z?6s3}N^H5O=PQqwYo~jg2X8-j7Swj!zWMEa$Jg9LlG`Z{!>s+xTWk5x;e8m76~w2{ z4uIj9%&-e@y!BRv)hP46)szVZV-c+!b5)!R-vbd}X%{lw9B~@$YLxa+UC6YUbq;P{ zA1*b-yG@) zjdr|N+&Eeq;FuQS6w+mGq-Zx`y&2!xZeE}hBa@Q~@)%)#M30P3j&AW~y2Ex>*%GuKW#H7z1A&=t zkZh-v8N=cExN6#PV`$!lIL z^oBFX;~Gsv&%V`%H8Ns?vyi?|erM}5{Lu(^^n8gqB|6uz%Jf84HnwZHY>z~&vpoIjuI z4EGtGdp_x(ZSQRk1o!xUlOUCWK1LV@+(NU=##*Hrr}(7S!5J3vAmBe98am}kG$`zQR5>+s;=6_P z_)%%x!fiVNg(oHg(@A#m;xG;AM;L2tALy9sF1RYf(2)~>3EBm^xu7+e4%b}2@kpWt zZ@af9zpbL=Fj=M#a)bWWBU3oV62DK#Jeh$lqa=!kpayH#d9W}J`CV_FB66#3;Vbv) zJTau>hiN0NfSt(qH_}x#p4hoEY%31xFlBk0Ym~bJ865bK)b3h`0Slse;Q#R)%LejPfQH`mH-M=j#_dfSp&hPC0Y1#X< za&>Q_?$zG({>=XG&fUWOtNV~2A*-;ZQB*Wi5{6Vx&G_Z1s4UF% zM8gjvEEq>+OOj0+`P$#Iyq_1dl$jRhhcb|87HD0&5=cXV9E^SoPNCReFVtRh$^|e) z99>KGEUNXiolV^YNj@zQd#W1q6B5*m7a=N?@yd);q$0g4FIm^TeVr%GbEX zBflyssf|@E8eFubq?E~K+b_I11;KSkTk8C_6POFLb3LlzBU7n0D6D%uvdK6Hx3=y?sK_($tMs}G3%)F-+kB1m9 zX@J);UI~jMCRE7p0^vk^of1p~ZI8k1^B?K)!lq+P$Z+XvJE?N1umgR1c7ws}R&5&< zG+V#7-ROf^I#bGK*Z<6q`VDeGIu&aCa)h<|Et1TK7edt~v|$L?m6ShWIi>)nHKVK;P8__KW<=1e$T7?lq)gI~1Q6h8 zA*g0z?%=5Sj({ynD2lJ>DjJi$groc@sa~!~jf{8Fa5~RxT@7J`5#(D2H!H0tM4)x; zgiv0`2mw!>nOcz>D(ErLr15YI>WKDoA}lxyUW?Y?U`i!{R?62b#xapT&NdD!f^t33 zwRI8fqtlc9)G56bHEAW~8ytPw4Ryw74$B()L@N`+cnr5ocKMw8{sq`WxX%II{;#$3 z3NXeF77f$L)ZjvC+z}p$`1_PDWxUo8$boG7*u#C{u0H(h_Ag6mHy zOQ@}4G(4(ZMUJL4DZvAI#Ul?*-O4|PPK7zouONZ>8kz^X(!vRss$%a%b?L*%m0eQg z;)l_zTH%>OlJIJniULl29sg0&owCnt*}Wh08{?wv z@3`}}QRgij!!{X)kg>dwx8*LT-BM>bfCwu?7!-o{D|&lJGM zgvu%_KvUhD{%KF@tiQr9WwtaYrec6=WnkX)^PTKAqC9}ft$^Ew!O#>+5i%7v5tyi$ zGCe4LgX0>M5avb7@ICDJn%!Epcp4x#Lm;J+@s>eIL~@GbsY)OBXTg58$e$A!udmD# z>6o#ilq7x_Bt^0?IWJx5^co@bxpvSuPgBjeL|GuUMjfv!Sf*)`EGtlg7fp9wqEM^$92kLfN^q|}yAGsI%mgRnIZ1ua)Sw3UDdF*@1{`9J~! zdDDsWM1XxDiXEaN)SQ{uk4zDY312O%w?oSz17_xVsKHnUxvbZUrhFKEcBFJNX~t(2 zLn17^DT_c)O?-EA3OyK8HMKRVhh-_rD;5?9sr)BMewlEx?>k4>(tXzZ zjIY$Kg0DU8d6)(cUNjS)#lT2#Ky1FZoUqh`fsC*|OBF@95&m15gv^+kJ0{b|SPO0< z8SyZIUVC4xvV$KO8tpej@V~Z5<%@wAKQ>478C^m4F%(qd1jzUxmAGVUhiQ;ypVEl9 zCIyH)K3fnx;^{LXO@~eBo-EigsH`EhV4t&e=b3WWg4G&Ra!ziV{h1todK-EX;tcM}H&W^-4@cd)l!c6`)G`qSs!zxkQA_R)~} za`!K7{Q;<7l0h~x#gf}=)N+6!9`y@0Ax2(D9;!;)sVs$XEGa8PM!sLE#auA+>YFm5 zScg7!J}^xcVG*(9BVR0smUy&~LO>QBQab&!?V^f!(ai>Xy{h;`2Lm-qs%pfQNVI03 zOoM=ViOLbqR6$s?i^Z3lspHb^#;M8S4!l@$D{TASi8kB_KbM49mI+_cu#1JIkv5a^ z%Al-*;Pi0Tt>k{ZT#9VPYYbipBR7RFlfIrnw{W<5RLoAS@A!}QHzr*omgdQdkL~f5 z$?Oi50D1exr^t+z&2RbI2C|2G$36j{1Ei7;eVRg#QA;X4&1%ju9S>5@X_atQqMu+# zRE^AZFF9}+KaHpqR(8g&@R`csT37QZDljA?R7rKR2u`I+$u3pk8Bb62n8zV;bh3%k zxl!&C8(QP*r9f)jivdnWgqM9+9!yY~bu;j4tj@6AD0?v7M8zUz6jprMSXbGFe#x|P za~fw|oIE*64Hze6gD_ow+R`y~d<&LZfoLvUBJ&n23v)Y#&GoVRW*5rimW z`It&pW^YB}r<*erU8v7{5H9)lA_lITSX0(9>c9$c=XibeV$^ZA*IX+e4hizaU#eohA%mahpZ~PQP4>b>k z9G(v0a}*l-tqRcH(3TBc1_ngmm)1VVijJ>)wmUDftczS*=w6#>f< z;gUu>V9^iglOePhYJJL{FgO(vpO(!**JkB+GuBt7Y$C%l~@}ROVyGpk&+U`@|^GdW_~lzAJ0rOnas(VGn34@bKlo}yg zpQhfS~+`641ygBlbsMMx}OaaKFCIJoz3LML3JkCFH zP3XKG7eXElZ$1>G*s2J%wq3nqW6^Kjg4_0fK4s7h_QfDD(<{pPcFl?bi%OcJ6W*%6 zDiFT><<3r~#ODygUG#n3apw4tXNF;(s_Ityj~HFpl#I4XsWKy0A?>hsytSW2GF2{AH3s#RW}MB#pjY`d$kpDT&J`30AU^S*{UARcMkyw1i*McSTK0J!s4m`?>}0hI=2 zn_(nNmG=W*OV!Iz&eL-yqzG2gQ)rFztVDx$og(tBrN=3be_@8=sAv!JrL+UEWO3`1*9c^Wp0PR z+bL%uM=ot!-O4#F0sdURlc8V|4iyV6zzu%0&3?jgFo zZL(l$Fk8)*wpe->@s-Q3j%niCJ@xp??JH7B0;?(ZBa*E%fMeY?^hC=ghZYl_9o>eO zTX7^K7tVSp<*u1Iw8jQVhHy=18S)5@!pH6o>+oT73o4weD5nt_hHPvg1FH!Y85-%( zoL{N-@Z0M&Qi+vnr6@<fqJ&j&e>nP+!$nKK{B?HaWVmUJVJAV!Glhb<+M_M#g1 zms}^LR$3;HB%vY9apIX-+L1qsI#J8a`a4&(9lZ5A0lvEbWL%m^`hc$lC$sApU)z8o z3}*`~Q}T1Rwk%J%YevMK&wd(y|BdjsrVE;($6v`d|HeXt_R-qM-W5W|u0)!`lVW;@ zqkKwp4JaJ;Q_xMVxWS>g+>94%S~#SUY(yN}%f;5#jqKZ1tzZ2CT;G)zN zn3hf~C`apX8GmjhC?NHSC958qC6Ov>pmcaLmM-NKeem~qU$Ix4F>_^ii^srYJu)3L zWRx9e^vzZcY(m@L-(03K(m`x~IOE?@OvE%(Ny=$8vo=a$6;xor7gHl<>y>d@_bfae z%0w~`NxxYl%RUL2op^>s$O}UE+bbg#oS^m<&B61Wh{&NqO=F7SB>ug?mB{+Rq7bC| z)R)Y9jJ8jyN7c!>z9d)VNVT1j4?b~fD*Yzi&9OHkYBL~uj$s>Q>SKDxFSl>eO)E)k z&rM-~jtm^U(U=oi!hw3#_yg;E$&aMsoztKS?K$0|ow$Ay?f$+9lsuIo^YyBj6p$C# zY_BqVM}~?&RhnA0LsOgs({iap+1Xhy`LRsaNJM_iD!a@?TJog!`VZtg!(id*do4(hkNLki zjFVl5Q(gxepnRB<>|WeK-W-m%KVzj5lfoiZx;RU*w|2{iYKU^h;bs%m{-dFnl;kK^ zT9a z%<@mk)MeQj>;1P;#Ola2HOJ5Ujup|E6UeNDc`%YiJYS9GRia&EDc|^^K#{1J8JGf> zF`QGZmaPVU#?H6XDzF*u6WP|4)s)*UpTPt$SpB`+=5Ra0z}rSpZq@BvfI5$hl7)uC zmljW=q@0X5F>}1rDEaAFhLAw&(tZ!O=)i_ddFQ`^vuIgpvwgXt6jvGaa24MZ-u0cK z$(KNc`x&4b?ml&9J}sJNwyEY%-P4HOqHx0wO19byzQ`uNdwjk%n7h_fB>-p9xSZek zFS)pjxL>F!(tET6c#3z_CIBTrxb;h$tp0wF_E_0I(wdK99O7f?q1arq-~Foy3Ec;X z7Zxh#J4WnQg%A@KNQme7H(=t2Oj5-Nz-lakQLeUfEjJ0X=cXsl)bf=~zUfY{y^0RC zSu`V#0RopH6}4s>(7a5x>B`BIxL*daquKez&>r$9`mfxZZ68DKapwm~e6z-gObBEr zU`KD8ud;iqs3@j;$?fz|3F(TzHuLfG^Sa@$_yQdsQ2jlM$yaaALaq_9A1X|SX2B+e zvY}rA`d64hk80wOD5456vTV4MrGJLS;t7AEz*R54p>-^XS$CdNn!W!B*I+3|GQQ(g zdqXty>UEB4*=t(Q;kp6}CUL1ovK>#52qC7cXiLw>=Gw0-Mz1xe+#-+h=a*p=8*Pwo zHEZfn{%!rMe1 zjn260LVxb8Gaj}Vv}v@bwVNU-)T6eK~v-0MR{bKy`mdRRw&SNOSI(gRd#~*kfYSyTtNK-<2 z-A@IFzZeSrENpnYDJh^T9d`k3G#=tQ8f5j$PtRo8+G0$we|_NTpk3`Zaqka1rCu++ z{snG3XrDQh(bI_$b|ZR^v^{0Ed5h(=4uJMIDXC25Dk37QvfA! z78PHS4I+HFAXz3EK@x2gL-tYQ6*pZ}D7{kwX)!}R`e+)Ic=h<8u{W|@fR&R2fwIChyeo8T)0(?O?d||c28;`ijkL{Q z)I&<+@oFqBJ*cOu4P%KXZ@M0|zaP^IJb@+kkl{B%;|9}bPZKE)=mJWx1HO%%UOW#( z+)TWy`1IE@#CBM-yWn}MHZ?L20S|D<{8+n~@NLzx=E_#}%?Ek!#W~|g-f8h=)yCMr1cF@{|JWS08n}v#&r27) z!Y<3Aq6K-THWGy_rDHH^mJ3RVk#`@3uKc*KM)=+QUXAO__U&^Lsj5Oq?=_T_ukGg% zh^_a)wIYZXuBFJwkclH(zQH;K8#(qa~{{7{&NT55KW zGMIKSo;?Aacb+uxM%eKFgu2M_I(Xk~fWG=8S)R!Pv22dJ;dbYCgr&@n$~P9qnRU{d zU}SRahq>I~t|WZK0;MPzf8A}#E_BLz*SDe$vBr;o=8)Ws9=7E$(r^D>C7n|3L4Pn(HM${d@Nx_=@J9042^%Axc3@{6GT6I3}-qJq3bzm>=*sSZ?RN z9B2ItDMi(FqJ9c#^!LSa#m$5mKew{|2X2Er;#hCKYNChkmY3x<#FGydF4Ul1%gfGv z{6=bLv*u%myH!=x&a!#lRFRN*$TI@yjj_UI;^e&IsIfEiF%c&ekb$hj13#O_aaQrc zUMvOm&;iX%tjF%4Q|xh=mQJs>Plusp=X+k(u_oNvYWEsBueX(160_PU4?~GW3SZW9 z$N;(w!fe5rQxS)$6ciiI^LxpNgdDjHj*2cNCUyPtLCqLx5KoC!ySRbb;*wQ^})M1^pBQQ zsexeaVNE=l)&@Ga`?&o*a6`0p&Ao$=p5sz#f+>D>A0(Bpby`Q>n-E|aDXXOS!-?-Y z1|&NMHD}-6FhWmpwQfX`I$t#fIm}TywvR$QTuI}z(UOX^GJD?@3!J|PY3l-?K)GXe z_tzW|N0@z}rlN?`6%HVj4kGU?DoC0`ns8!dTbn9gn~TG?*PqT_Xl(6;9Ob_yj6N43 zlO#D{M7~HsowM6uhQp02&F}HnJ|Ij{{pqDZna+B)U)t1TBQKALolXVg2^_A%N`mB3 zoLv+>wrcy~nLf}EG!%UjU9VurpQ14Rd+tK%V{0_VBs5(yIN#k@gqS*MeIGIV=T`-s zfY^u>yt1q>mSHwO5fJKgGVCr?#%Rp#3-p5>f<4TqIjN)wgG!47$Y<)K^?ctmX#w&= zH_oV)U#<16%ia8&hmog55Ywtq^rGDStml|cN}oU~B`^)jMZW08VghvtL0%nWt{$bs zjyyLv7fDjPmwu^A0Y#jLv+1NgzrGK0V4C+m;A)F1wT^fpX&%)V>L^^k4Ek@^%a_# zEtmeT7CLi#Ww=q9T&2#k5iwa@cgOkf8Z|}BsmuF8>m*daSDY96SaFNHCb59U_{Fb) zl-k=KlJ~|kIhi2^BepycAWeefV|FE)Bo>!EhB85%_$Ff}+aX$mw0$ap^-X6f*-*G_ zLs*9DzRAhSfld#nT&gzK&;M3j906<3`N=~vIw|4f)qwJC`;3YN|6=4tD?shW{SUIb zTs%2O(+|8!r}Q=D6<+br_}OtL3JxGMTx(FotAPj$bnZZ<{Q35`AB&oCIo?r`4Qr~; zJ_b4rHW&TM=k6C^i@J_#I zg4*mpc|m)=W?*>_k38Ol9sKI0&+l^&)8`$d$Je{*xT`Yq4-bxF{x~Gg0m7HgKuNWL zIZ=|ly}59BnEH8xdh{>9_;6SQ=P;~U6{dKlJ3gAtDoI7ZVh*xpW3? zaNAQYm3#xwaMOvK3w#Y&71>V>TY0jk53-waJ?FFW3^O1s4EC>4kLkyEj-L%L9&Z&N ziex#(Y=^nP5}#kFZ`SHQ)ksY){;qQX-L&rRL=7ZJnedQA|+|D$C>|(HBJEza3@6Qnm-oW0gX(_EK#bNRo+VYfC|P z(CRhRA~SEZ*pg85#f&i63+K!;stq^#I8c0@Ug2RQz!dW^EnCt&xc~s{3PWE0KxMV~ zx6696 z=*5i$Hks*M^N^(V@o}u;2^1@O!ce^F{KKVh>NQCddS4RWh+VPNlKp9y4&~#UWSf}! zVQFRI^9>xL)zhH!`eT3mzm8=uN2%sn3NL}22UGU+Sx zhnFE9ml0obD77dFhrAl%Df|dO+k^NFw!aVmbPn7emgJXi&eZ!H7j(`xUnh#`Tm|Pv z4nz%xAM$Qi{SCh?M|F9vd=}KK#?s~e8N#!{0$-%w?c}qs4Ads)a-Z;W5REOwFZe9Y zuJ`w^Z5R@j#XjDxqv}K#<%S!h+ZZxl)BTI1vf*v=t7vL;G55irLt5UscUORlr{e&# zm;Nmz!u<4!@%X!rFMH{9GHkypcB#J#j1%|X1vD-;iWI5I*3lElOMt>sY9H}I!y2*q zaWdKbYPzDL*Z$TG&6{0+x0J<8j?WyA5MT~-I`goeVv*P|*mN76Hp}f##Zz|sP4Oc0 zbcV?Md{HzE8Mcw_C-+<^={YXiyK<}suc^qb6Z2$t`S5V#g+ll5zkhe;K2KS9W$bcom+ka$kU!8R8BtoKXqHFnXM{#~rwPGa%AME*&#D~q zaztDmyo}zlx7--JOFsUSbG+Z!%UJf0J=jQKB!tctcfl6dGFie>6sV@XpxCasD`szU zZ7^YNuu(_na)do$Fd=7idzLH$i;aklyxB0^JrF&N*fvalFFk6G+>VawmZEz+Lv|b$ zHp;Fh&##Q*Vs@MS7Y^6K6piK1_U)ddUz-b)jS=1lVcm@cV+(DS6N+&nYW^xmq+WU{ zZ&Ww#=b+Q~??sTaXnWG%zi<2hDG^pUw6KJs2DXxP7?{hBirr`gjbBc&hg&ycd(T9Q zsJ%xUdrpS~^9TEF=NqGeDe2YVJ*n8g$@8&bC?`4w7U)FG8Ca`m)aja`ACg3NqR$15 z;k4=n9k%SXu1V7eE|m0O2X{bLwT%IM89F)P;iCj6El0)JsKOggQDGel8i@bR?E>4T0cWZULs?ft zg%;36s<8dBF2ng-8o1xwzp|wj*qp*uohP{6QkXkCv=udHTvNwGiALJUJBbf}pLnqU zGdUF%_k`3Zg#85fB6$eJ`Ix2?A#C7|KdG!%4L+vwf=C!pP=y$YqeE3&oF{I@y|P9L z%RB3nvTIZMN=hn2k@s>}2wqD7p?)?IAETqx;`vs@T&iG@Wg(B>s5|MxV2 zHgc9zDr*3ZcoxP_(Ez_mdbVs22Rg+$g_s0~WQN#O7~E2>HxO6Lo1VQO%xC`K#S5ky z_u84rcaJv6f-|MEwJ~REC48S%6~w1lS8*|W z7AiAmoDwcvz5p#|Oxf5WN`+3KjK}}L4(E>u)j!(((m#YC@eqVWYv)Q|@6mgwqkK>w zUbt3};$AGbx+U&Q^5(S%HnulOB3t;Qy|&`?dv;1Gn167r=k;%2(G#^wx1zfhumL+# zBD;)OvPbXk>g~Oh;oDg@OJkE83F+MTGZkS`U7F}6I9hefPsCcWKIux$%0g}(Mgb5Z zxXEb-4%|hLYh7*>H|}wa3V-FOpcpw%6>-vG#;Y>yee zk)5LyZ3))$LnQ`Qn8U&pxF>)TN?&<14*hOpT>`S=9fqUr%+RG^Q4z-nb5vOL{!YIs zl^)(h{pu7;TM+1FygyT1O!e1<)1##{hx|6qtu50!BD-+^h&#UGZQ32eH8DEWtaBUB z{&s7UyL23f5%qx}7iGQ&j0!8p(vJG1F2)gTdJdfbH&871-w`EG!HM4a0IGay!xnNH zZ0W*-&8`aMtK-iB(XTEuLkT&YX&@aNzxZo;EXS!kEi4igOUDQv9*G=G^u&Zwdk+X; zLvwL=bVLB>Q2DK{N)cFB%pq9U_*g)v?FfvEY#d&lZERE-JDj<%MbJzLf;uTmq8u;3 zUYgNqlF)Q)POM}dk-jJm361epYDX8$tAmu zgqP+Fo5Hrzk4Fi|ALoy|VF#ZD6u-5B*fQ|1q&JfBZ`m|foiIoXCpyM>9vp=b)rqsY z;a$=Q%V#a()JurEZmd9-HiWRfwLZJDIR+vJBSUWzjE5apmLs5dEb0P>8PP>lI?2{+ z4&RMKJssTJ-Cx*#RGyQdqvZ(YP%X?|+uHscytn)$dOIMxePz3E@Ps2-tUJ-TLlMt7 z)Cm|Y31(vcDRiCOabE61JJsMl&QSOFMu>Z8TT`Qg?cKO;mzx#xyFLCdfe!rQ=9Gh1 zk<{4F4Q!V#_f9J=GRX3Vuid6+h$2TA{(U>gAyVf%6Q1{_LxqHP@ zpaDv_@Z8VmW~o$ile}jnk1#@C%Ev(-gNUp0WBhUd>t*j@-Yp3th`rxm^9ydvNm2K> z-^xlHw#S)>xraV=v_V5vUSs6*00bIt#LH5xnM&?_ZzM4aw<{fyt&$`8wOPFtiH(}i zSL}_->cqJa{Zv$NoV#Ui{?*)Bl3r-%598XJpF?VATf?-l0OY5$!D=2q2Pu?9VU=eU zhtlx*xmWv&!&w<_&*4L1lsPFFw>Y8wNS7VwOxE96$`Ba%#lnM$Q006 zPhH9bYw5c?9*4tS=w)BGG?cKj?RQmBIh&%`_zApJt*pu`_J%goP z3wPUZ zk&6UXP^5S&!*3*+D9fxKej1HSWa>2Ad^>Y8%s%izR;B_scCtT={yn)Z{QKaBvW01et~Kdr?bLvwI0^jq#EA4LaBZ_l z%$8r3G!#`=dA%eF;5GX`ug>Mlhz>0(rI*&bpH^=S3{Iy=JyK8?hdH``Aa+<5rEezp zSLBGK_wQbjxsOmJEOsiGl9&M`+MWivHsdrRK^m|lp%sUY z0OVCrcz~jZwl5Aev>79JeAdFz149Mu*Y;xCw58N>K0LHV5`#ph9flU`fI?D_odJRf znI3yghlPS7t0P+MrhssiLrip63Kn+I*GmgM-sq)E9dFGa?5-wg#daO+ji>icV^JNb zRLpQ6;dgTXzx9B1MDV?NjSnvCnfWY%rTw&mwFnSNK3Lg5>~ev&+)v0^v)Ef0uezF- z<4a()V@DlBrq?(oMXLqplxqMI82RQ={p72ix-ptBga`_Uf|t4n>(f=YRPi z;rQ=zFHPj|S?@75rin~(IvVIb9EUN6Xn#|B83k?m^yL@}*zm$(xD-psN7vkBFw9VY zx(6%gvF%)q$@OYO{ntlpH-mBjBx3Q73 zqqA819RiN!*aTSDZ;PI=ZR*j|pwq#eY0S=$P0qo>lcC_Ah+M_S@K*r(6ygS7c?+s5 z;}P+Pw+}wp0jx#;GHSM4LqkCoj;VwJL>K*z5G*K>n~XtymM+XCUnaHdLyVt8bD-T? zDh|Y#NZy*6+Bgc^UvR8;uWhm7vaFuU8FQ1!LLuQ|sg$-r7}of#*9+7iz>TyL|RF9D6IZa~%WleI)>&A6{XMXq2=+&c;{;!!9e zP1P`eAZmLyUF0bAH~}ot#|}CAeqbwuvNNGLRD?8bk%WIrKMH#f6GV=3j%mlcg9MGu z)dkAsJpO5t+iBu>rqCtI?@lVi&2fY&4mc^eJ@FgVT#N!t5Hxgj(lC42p+xX@_O_RC z(0r&CdP36cUGzP4+|zM!nZyg|hBF>==$Anf+m^g2QVY5W1!j7`Khur_cV9OA>Y$Lx zv01;sVL=6kP|*Cz8!9EU@>P^zO#})05MhgsLtkSinv9)dpY59~5Oz`z=*DRbKCG>zT)y!hG5 z-L!=~j$=A<)hGhu82QeOtcszIq zY*W%>kI1n!f!>25k}xc$xUKDA9UP(d-_J8>U@JDwD1 zbUMg6rpAH=;4S>|R^w4Eh1jWhzJ&ix84KLX zE5`m!NWXu!^y>R>Fs`)_(PeKF0Kx&senkd)BuHj<)b}rL?uXe9lgNziW#fa_ri}6M z!&MNx!#FsI*&AXUIt)jmp-x?YxsPW-;>Ump7#O5h34n1-{PBV5F_^(UnkYUvAcJ$7 z&AP^(4AM)bzYCw~fdb~*I(N&vZSu^S5WrJ1Z7)mFrvyAKtGy+I+bEp2a3 zG5qSDkY=mDB9!fM!eB>=A2P(fvp+;bg&V<9)UWB`ir9)jNm0L{m{SoI_FD?J_or{s z2;bjdQIxI%JN}bgr_5S5&Tk_$iSSDkM!1|n-A9N8G%1$q_6Q;D z8d1w*r2rcKySe)m^nOl3^e)r-##eeYev!4BWGz!7)|Q01X)JF-()%zf*`%#<@+{Z4 z#HzRnKrapoxpjl~d%6?-fQT(;j>+{2eGO;Un!c|qMEW2GhP~Qb9PUUw8VPm)qqOd# zg6ifaWt$4Tv#5gkptdl^N7l1xVkq(^neP<4k(im={)E}%+w!Ke}GbN zGPSAE)r|*rQ#+q_N;5Jwq8Cpd>@S;wUSR48cnemc?))45+Y$&FK0f5s!7*q2Gd|-+ z*;5~U8ls0|{jGv+ZrEWYUctEwqJEUi*IoX>cq<4i~6~^tH<%M}M zXlNV@q+Sa;3Q8YwsL;@}xq?beUzsz8zZaZBx4^BftYjn+aXt-7t1IS$N{pa%S>y*8=e>s<~s;gecUB7GbE_Y)>7=QFeQ(w|2K~!sLEem490rH@Z zYDpMR(nE-D;Azw|76^OoOK4M_cX-3$TiVsf@_tHY(vcp)ZC5N%XkQO2u5Xe==v}xT zXPgP?ZU)z=UnZpfw_hTF)4KJP2QJEyj!_Uh0deZ5!S>fcy8ez|9p zDhDCe?@X8>^&`LUdBt(HGm$=>r-bBMvz4KYE@bBVo)87MDA8#UoXMBRA`l@n_IRfA zXKX%Qt9`m5`QJ5!9^&ge6H*-NHpbqB<9CpaRVe3kCZhAnx>J>3*RwII5a)KpxgoYs zxmM`fJm0rarqEy&ue7P!S~I(bk zY^{x~k(%kPAH)QUpk6`rhbNl=k3-g(G{l88?`MY|#hyTA%;86FN0#7*mzbkk@ zcJsL5;_vGp5cv3!3wV{Q!B)lKLDB#JVBjOvV_z>n4|(@TEe~>nVO@!SC_EZ;(FN;-mNN1|xuGr4C>Q@5 zE$H(g5cdraOB-8?W_(ySV~w3LU7 zmb5k0RM8Zthj#b4OvaVVmf)Z2}uB3EMN?B1!1)`(~QHFz+ zlr&Uf8cJ$Xe}AL_ZFm<~4U0<#f9nFCw4~jMM4Sc$;^*h5;HRR1#k)b2;BYuZQ5mAF z3079+($L^)w^61AiOOMh&^2WM*fUtkR3Z$|+x zgOE@-h?0UL#K(uTukWh~L<{u)n(?oz36}miG{gc;z~00=1MzS@wJQwx?*CTASqNC8 zaTV_Y1O?@N3F~~*2aO>bUDA>U-YB?uxM;wYQD|i}R0XW)qKF2&LRA&Pa3?1xFx*uM zu7*~1a#B)L-^KY?d6=r=MHK^;i%>NsB_(~Ru9_O$0ICnwgQ}@QVY8$A{C~=7=;6^QA{K9n#d`0uz}y{6#1h=GI4M0nDOqa|j0@I}@Ea#WKQ?>` zjrZ_HyBOfHK2qOZtl{x*>fuUgs4GAgSE#cR7^2u7dzZK{!15i8s4b02w*M|7HR3@ZUT_V}Rtr16h&_R(}Kn9lm39>7pg6f0ki) z%fXMvw?O-3zw#&4iNvz)Rkj46N)~!Q(9Z&uG#;C)%E=Eq@=p=s^-ywl#;mx5E zMo0F`p5@1jnNu%J#UIi0(G_Six=eP(r=E_lp4;em+dAuI>X)rj-Hr_SHrv6s%}Dy9 z{Kw<_F?GV16KeHw>sl$s@isb8?{bk+QcXrYAh0pu;BL zt^QZw&^BnGj*je0f*$^J30FRaR=>1yU}$P;>T8ZR`+1IS!6$miTSvKfs!~;6Csq4yjU*iR7Atxy-yqUT4-dcS3};A>K*f2M#pln+YH?qn#EvT7`; z;UdG^`YYF}FlC3H67R2YkuI+!pBJWr82g7NQP{%=>Vo*N#H48iKR2;vlqciQVMcDh z)#4uSk`aZSb(9ExRJqYJvrB<7{scjmzx}l8R`?RKe&e!aUAb3J_I^q2&GZq`Tk3J~ z3!>3FQH2#^CBYbZim&{Mk%7b1eeSCU&G#i8SHC9FkCSV!TFNDuufEo; ztQ5Ov@F*HX$rz?(jXD(dGwxoEMi^2ulkY_jqs=KpmYe-vMX6ikkPvtoVWJ)Xr?+to zl&$sATTQP>>l{c{l~nU-0vtsAH9(>^b&glG?7hQtvYV^xXeBc^z>`@UKB?O^RBcCQG-T#_q zZ106Et4B2cnVftjn8O3+n>V)-BZhfi+Oxlmq)^wVDcyj_9ORN(Q6g4$s{+W3fRP%F zZ}SXIy8^_7fuZ5nz~F0>!uq2v!-1Rge)N<+dPs=Bx3~9c?|j7%h&Lj2x=B^*c>;D> z(`}8g$4{Q*2d<99ST|fsLFnDc_YAGy$Lzi_`98CcOw-m;R+bLDv;K`8+O3&_A>(bz(i;N~l<0Mg4B&5SemweR-<2Lu+MlLRTi|z0j2d8%LxD?et-l|J8WTl(m;dt!XAhA zVMQS2?P>l?U-AjZ_d?!peb+kqA**MaO@^A3J?EIhSa3K-U+*qT9+`X-7^NrbBk_2c zXFj%FYU7@MwlFdn45QVEc#4a8LAQ617ljA1uWdWAjM;xc^=LdvI_ z4TtEbjRpxqq~b(9TQ<@-;?op5NOwV3(wgSKuszJDlWRrko=L6zr4xUUdLfCh+C$%F z-&=l>xI%7B`M%M7vSY{=`*qVDk)j%S_ArmYyAkK+IEG1Sl^F7~X8){bKt`%pT-08P z{AnS(ScrX+NSc1sWPwI(sD)2vr9LUPF7Xe*W} z@u2N&ZF52G z;UU|b<;5>g?gR4y)S*xNNW$?hD0g>ROWN-fUzLFfp2?ivT4+3gjnw=#rY8?sFL>CT z9lW!_q$kwoN2(mRq>0Oa6?|wVqzJNNy?ghr%`MH}_58a*H@jN}xT+<=ge6i~TLC#_ zy(_&CL8Ij^Sk{D#@U}0GHQOaY9BUKON2G`W#tRLhmNcEUmaB+%oH-jv-nzV%&S%E3 z9t7=gckgUY=yWvS801HZt5a4g6koXFg(h#ew6wgQot=HML^js)spLnB=I2!|e;dGd zJWIf+u-KmPWvN+*J)-&hf~TG(O*?M%_Z&SdBct8tuG&9^Ll)f@ne^@6n6F_CUDm63 z#yQq_&Wdi+b-+&|pc6 zIz&~pNpO%ToRi#Mh)KYiuTM_qo;t+?F~7tc(@4n9$(aDl3sWzIS+P1owwI!0Z+phw zJ(t)56}^rUUtFnOq1j#4Ui+NW_~60G_?YPEc^fA+{)eZ3E4Kw}_JkH%)8xle{f7RS z95h!dwsH^iIa)8st>B&eXL`Eh?4UvZoD?Yx$i*D9Q~~2w+te_5PLk-O^z^IrqMo6{ zMPv)7!46fplY^O03#N}yFI+sf`BuK@T=xC$gB5FVTHlqJFnBzWxlz0^q1trXrfp$xR>T6hHd#a{LVq!w$XWL%08b-&oP>8l&bXXdK2E-lt=4_t^mghcD zzduXvtTtPSRkRfs_H+Z;#?{2S1F7w`x3#sE5Er*gb-BjjgLv$~i?Z2|&#x_wu=^R_ z=QZNJ>R!f4XxVP{bp#`f(TGA;mCJ-@~EjC+0@Ijq}IKT9Z+gf)6$~h{RAdp{KyO``dS+{ zF}cn4Q~}v|Ajku#h84Qq1KUlI;19M)WMTA5!`G7HCST2a<>15hg5JMa7a;-b<^6JS zq&Of3vcZo2;|ZRpj`RxwXd83U7B*c0OJCY>W~?hs6i(Q=6dYcbJxTAH@jQQgh7`sp z7tB$KXiOejUbE@dwx@KD;_6Iv(!0dl$I8*7z2w+|8<$s|kqM7 zvvUBMxva3gy7ol~O1UgL+!S!tANKb4wl(=CAf_Y`7`-F(vu00nkE`P{9!Imxb0Zs1 z+pS8Xp5`$l@58}EjePU2Np(j}2E8Bp;PEAY6!nO&m6UA0VCEqw7WV|9F&K;zYw4xf z%2f&%X>xR>_l0vpW6S~An7TxJBdj3&logP;y|b^{`h`Ybm3WrhS}*32!uEjAojb<@ zE_27tz=FcwndE&|Se>n7v-aHUd8 zXIoG)ezwn~kSj=D==*gSjD;=hbr0MjMDjq2pEt4CGd=RDey8VS7Qo2}?qYasO1U_Y zAN?eDxAn}}*jU!HS%gL=qd1|l$Dew^QE)EWv%DX7#uBJZO{~sNi!%k%XB+;q63u-2 zjxtn`>x^$}QwY;G9?Y){7=0DHzOaB(InT;T^}caj5SgK4YGxK)^SkQX@sc|yNnuZK zGl3|yI7a669NQ0+4#cSITr_=a4$D^c7PkI82AJ(|sC_auIoUH34IJOClz4BuMT0+m z3%LfeS5s3`DC3YaF~BixoS33EaJGvA_P{}NX4c6V3e;-^v-GA7aJwLGt}Yhm=Rc-@ z!f*-&aHF_67Z8DD+jfJ9`oZpIHi&OPw$T!5?SEVTTIyff$rvv11XUyeG6WGj?Y;`D z{{6I7bwCk&6c#u3vUTAQaEA)uxT?^h<`e15W4Hc0)2JDty(gAj00NNgDUVN)iaoVWA@95|^#IY%nsEQWo^?}F0ZU&lU06u;m zhykwV$^I#*_uPQ>QKYeZuuj&Ol+5viLhI$g22M778_CQ(+4}ZMVmuemo1_E>dN6JK zmGITOF%DjUm+Z0^1SPN1kbb4c*Eit)UtLbI*7oDmIn}zFIAtL(G>FIz=3CPM5>zoh zK7I~o;!#tQ7Itk@Mw+v&l_Pm^Hu*}t&3Ze7w5*|JjPj7b$UClGkq^AX^uOLNWm5JFGUM!5Hq|3R z6E~se4h3mJ)zm(T9y@kSNZ5Yl?$G%7xU5OZku@cI8W~!MphPidODOdz$XCTGXQoAO zs5L}pdy31>4bf^A2MHZ*FTI-^S`3nzRyC&APNnII1o*ijg zd_kUEfv+kze(Ie3G_0%REApX%=3}f-;#bAo=;3nbk!(XE|hPW_dQ6i5@9s-mAdUv>=iF~+NKP#PYT zZz*@DtE=nU)O|tN{6291Y4I6e+@mP0n{H+4iecv=OtaF1xaQ8qSmLA7m1tv0Q|jYT zZeFXjl#|{wQ@N3&uoFvt&d?M0I+NE*Mxe2SYv)^najQn<#C_-;`eUv8JP;|8bwuR@ z9-o3!-aS5=`;z^kKY#|{?me|hF8Ur?fURKk*4*^1n92z83!w8)BsBCJ!m zGU|Xc0mQ>w^qyz(V$;vvwB0sXsIHLCY=Jxoxbp9|;dUEtb$WN6MC=C`zB}f} literal 0 HcmV?d00001 diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/download.js b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/download.js new file mode 100644 index 000000000..19e9bf2ce --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/download.js @@ -0,0 +1,191 @@ +/* + * 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. + */ + +var modalPopup = ".wr-modalpopup"; +var modalPopupContainer = modalPopup + " .modalpopup-container"; +var modalPopupContent = modalPopup + " .modalpopup-content"; +var body = "body"; + +/* + * set popup maximum height function. + */ +function setPopupMaxHeight() { + $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30))); + $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2))); +} + +/* + * show popup function. + */ +function showPopup() { + $(modalPopup).show(); + setPopupMaxHeight(); + $('#downloadForm').validate({ + rules: { + deviceName: { + minlength: 4, + required: true + } + }, + highlight: function (element) { + $(element).closest('.control-group').removeClass('success').addClass('error'); + }, + success: function (element) { + $(element).closest('.control-group').removeClass('error').addClass('success'); + $('label[for=deviceName]').remove(); + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); + if (deviceType == 'digitaldisplay'){ + $('.sketchType').remove(); + $('input[name="sketchType"][value="digitaldisplay"]').prop('checked', true); + $("label[for='digitaldisplay']").text("Simple Agent"); + }else{ + $('.sketchTypes').remove(); + } +} + +/* + * hide popup function. + */ +function hidePopup() { + $('label[for=deviceName]').remove(); + $('.control-group').removeClass('success').removeClass('error'); + $(modalPopupContent).html(''); + $(modalPopup).hide(); +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + attachEvents(); +}); + +function attachEvents() { + /** + * Following click function would execute + * when a user clicks on "Download" link + * on Device Management page in WSO2 DC Console. + */ + $("a.download-link").click(function () { + var sketchType = $(this).data("sketchtype"); + var deviceType = $(this).data("devicetype"); + var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link"; + var payload = {"sketchType": sketchType, "deviceType": deviceType}; + $(modalPopupContent).html($('#download-device-modal-content').html()); + showPopup(); + var deviceName; + $("a#download-device-download-link").click(function () { + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + $('label[for=deviceName]').remove(); + if (deviceName && deviceName.length >= 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 deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/; + if (deviceName && deviceNameFormat.test(deviceName)) { + $('#downloadForm').submit(); + hidePopup(); + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + showPopup(); + setTimeout(function () { + hidePopup(); + }, 1000); + }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 == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showPopup(); + } else 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/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/jquery.validate.js b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.hbs b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.hbs new file mode 100644 index 000000000..c516ec2b6 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.hbs @@ -0,0 +1,292 @@ +

      + +
      + +
      + +
      + +
      + +
      +

      What it Does

      +
      +

      Connect a Digital Message Display to WSO2 IoT Server and manage + it.

      +
      +

      What You Need

      +
      +
        +
      • + ITEM 01 +    Raspberry Pi with SD Card(Internet Enabled [Wifi or Ethernet]). +
      • +
      • + ITEM 02 +    A Digital Display with HDMI Cable. +
      • +
      • + STEP 03 +    Proceed to [Prepare] section. +
      +
      + + View API
        + + + Download Agent + +
      + +
      +
      + +
      + +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +

      +
      +
      +

      Prepare

      +
      +
        +
      • + 01 +    Connect a monitor to your RaspberryPi via HDMI cable. +
      • +
      • + 02 +    Configure RaspberryPi to connect to the Internet. +
      • +
      • + 03 +    Go ahead and [Download Agent] the Digital Display Agent. +
      • +
      • + 04 +    Unzip downloaded agent. +
      • +
      • + 05 +    Start Agent by running installpackages.sh followed by wso2Agent.sh +
      • +
      +
      +
      +
      +

      Digital-Display 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. +
      +
      +

      Click on the image to zoom

      +
      + + + +
      +
      + + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + {{js "/js/jquery.validate.js"}} +{{/zone}} diff --git a/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.json b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/org.wso2.carbon.device.mgt.iot.digitaldisplay.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.digital_display.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/digital-display-plugin/pom.xml b/components/iot-plugins/digital-display-plugin/pom.xml new file mode 100644 index 000000000..ff50040e3 --- /dev/null +++ b/components/iot-plugins/digital-display-plugin/pom.xml @@ -0,0 +1,61 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + digital-display-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api + org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api + org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin + org.wso2.carbon.device.mgt.iot.digitaldisplay.ui + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/pom.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/pom.xml new file mode 100644 index 000000000..5f70578fb --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/pom.xml @@ -0,0 +1,254 @@ + + + + drone-analyzer-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api + war + WSO2 Carbon - IoT Server Drone Analyzer Controller API + http://maven.apache.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.springframework + spring-context + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + provided + + + + commons-codec.wso2 + commons-codec + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.apache.commons + commons-collections4 + 4.0 + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + src/main/webapp/WEB-INF/web.xml + drone_analyzer + + + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneControllerService.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneControllerService.java new file mode 100644 index 000000000..17ea3c5d0 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneControllerService.java @@ -0,0 +1,82 @@ +/* + * 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.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl; + +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.util.DroneAnalyzerServiceUtils; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.controller.DroneController; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.controller.impl.DroneControllerImpl; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import java.util.concurrent.ConcurrentHashMap; + +@API( name="drone_analyzer", version="1.0.0", context="/drone_analyzer", tags = {"drone_analyzer"}) +@DeviceType( value = "drone_analyzer") +public class DroneControllerService { + + private static org.apache.commons.logging.Log log = LogFactory.getLog(DroneControllerService.class); + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private ConcurrentHashMap deviceToIpMap = new ConcurrentHashMap<>(); + private DroneController droneController = new DroneControllerImpl(); + + + @Path("controller/register/{deviceId}/{ip}/{port}") + @POST + public Response registerDeviceIP(@PathParam("deviceId") String deviceId, @PathParam("ip") String deviceIP, + @PathParam("port") String devicePort, @Context HttpServletResponse response) { + try { + String result; + String deviceHttpEndpoint = deviceIP + ":" + devicePort; + deviceToIpMap.put(deviceId, deviceHttpEndpoint); + result = "Device-IP Registered"; + response.setStatus(Response.Status.OK.getStatusCode()); + if (log.isDebugEnabled()) { + log.debug(result); + } + return Response.ok(Response.Status.OK.getStatusCode()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("controller/device/{deviceId}/send_command") + @POST + /*@Feature( code="send_command", name="Send Command", type="operation", + description="Send Commands to Drone")*/ + public Response droneController(@PathParam("deviceId") String deviceId, + @FormParam("action") String action, @FormParam("duration") String duration, + @FormParam("speed") String speed){ + try { + DroneAnalyzerServiceUtils.sendControlCommand(droneController, deviceId, action, Double.valueOf(speed), + Double.valueOf(duration)); + return Response.status(Response.Status.ACCEPTED).build(); + } catch (DeviceManagementException e) { + log.error("Drone command didn't success. Try again, \n"+ e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneRealTimeService.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneRealTimeService.java new file mode 100644 index 000000000..c0c85bc94 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/DroneRealTimeService.java @@ -0,0 +1,124 @@ +/* + * 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.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl; + + +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.transport.DroneAnalyzerXMPPConnector; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.trasformer.MessageTransformer; +import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; + +@ServerEndpoint("/datastream/drone_status") +public class DroneRealTimeService { + + private static org.apache.commons.logging.Log log = LogFactory.getLog(DroneRealTimeService.class); + private MessageTransformer messageController; + private DroneAnalyzerXMPPConnector xmppConnector; + + public DroneRealTimeService() { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + messageController = new MessageTransformer(); + xmppConnector = new DroneAnalyzerXMPPConnector(messageController); + if (XmppConfig.getInstance().isEnabled()){ + xmppConnector.connect(); + } else { + log.warn("XMPP disabled in 'devicemgt-config.xml'. Hence, DroneAnalyzerXMPPConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + private boolean waitForServerStartup() { + while (!IoTServerStartupListener.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + @OnOpen + public void onOpen(Session session){ + log.info(session.getId() + " has opened a connection"); + try { + session.getBasicRemote().sendText("Connection Established"); + } catch (IOException e) { + log.error( e.getMessage()+"\n"+ e); + } + } + + @OnMessage + public void onMessage(String message, Session session){ + while (true) { + try { + if (messageController != null && !messageController.isEmptyQueue()) { + String messageControllerMessage = messageController.getMessage(); + session.getBasicRemote().sendText(messageControllerMessage); + break; + } + Thread.sleep(DroneConstants.MINIMUM_TIME_DURATION); + } catch (IOException | InterruptedException ex) { + log.error(ex.getMessage(), ex); + break; + } + } + } + + @OnClose + public void onClose(Session session){ + try { + xmppConnector.disconnect(); + log.info("XMPP connection is disconnected"); + } + catch (Exception e) { + log.error(e.getMessage() + "\n" + e); + } + log.info("Session " + session.getId() + " has ended"); + } + + @OnError + public void onError(Session session, Throwable t) { + try { + session.getBasicRemote().sendText("Connection closed"); + xmppConnector.disconnect(); + log.info("XMPP connection is disconnected"); + } catch (Exception e) { + log.error(e.getMessage()+"\n"+ e); + } + log.info("Session " + session.getId() + " has ended"); + } + +} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/exception/DroneAnalyzerException.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/exception/DroneAnalyzerException.java new file mode 100644 index 000000000..7421c5932 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/exception/DroneAnalyzerException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.exception; + +public class DroneAnalyzerException extends Exception { + private static final long serialVersionUID = 118512086958330189L; + + public DroneAnalyzerException(String errorMessage) { + super(errorMessage); + } + + public DroneAnalyzerException(String errorMessage, Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/transport/DroneAnalyzerXMPPConnector.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/transport/DroneAnalyzerXMPPConnector.java new file mode 100644 index 000000000..a4130c06b --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/transport/DroneAnalyzerXMPPConnector.java @@ -0,0 +1,160 @@ +/* + * 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.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.packet.Message; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.trasformer.MessageTransformer; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.transport.xmpp.XMPPTransportHandler; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class DroneAnalyzerXMPPConnector extends XMPPTransportHandler { + private static Log log = LogFactory.getLog(DroneAnalyzerXMPPConnector.class); + + private static String xmppServerIP; + private static String xmppAdminUsername; + private static String xmppAdminPassword; + private static String xmppAdminAccountJID; + private MessageTransformer messageTransformer; + private ScheduledFuture connectorServiceHandler; + private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); + + public DroneAnalyzerXMPPConnector(MessageTransformer messageTransformer) { + super(XmppConfig.getInstance().getXmppServerIP(), XmppConfig.getInstance().getSERVER_CONNECTION_PORT()); + this.messageTransformer = messageTransformer; + } + + @Override + public void connect() { + Runnable connector = new Runnable() { + @Override + public void run() { + if (!isConnected()) { + try { + initConnector(); + connectToServer(); + loginToServer(xmppAdminUsername, xmppAdminPassword, null); + setFilterOnReceiver(xmppAdminAccountJID); + } catch (TransportHandlerException e) { + if (log.isDebugEnabled()) { + log.warn("Connection/Login to XMPP server at: " + server + " as " + + xmppAdminUsername + " failed for device-type [" + + DroneConstants.DEVICE_TYPE + "].", e); + } + } + } + } + }; + connectorServiceHandler = service.scheduleAtFixedRate(connector, 0, timeoutInterval, TimeUnit.MILLISECONDS); + } + + public void initConnector() { + xmppServerIP = XmppConfig.getInstance().getXmppServerIP(); + xmppAdminUsername = XmppConfig.getInstance().getXmppUsername(); + xmppAdminPassword = XmppConfig.getInstance().getXmppPassword(); + xmppAdminAccountJID = xmppAdminUsername + "@" + xmppServerIP; + } + + @Override + public void processIncomingMessage(Message message) throws TransportHandlerException { + try { + String from = message.getFrom(); + String inboundMessage = message.getBody(); + int indexOfSlash = from.indexOf("/"); + if (indexOfSlash == 0) { + if (log.isDebugEnabled()) { + log.debug("Required resource not available."); + } + } else { + String resource = from.substring(indexOfSlash + 1, from.length()); + if ((inboundMessage != null) && (resource.equals(DroneConstants.MESSAGE_RESOURCE))) { + messageTransformer.messageTranslater(inboundMessage); + } else { + if (log.isDebugEnabled()) { + log.debug("Message is empty or it is not belongs to " + xmppAdminUsername); + } + } + } + } catch (ArrayIndexOutOfBoundsException e) { + log.error("Wrong message format: input message", e); + } catch (RuntimeException e) { + log.error("Unexpected error has been occurred, ", e); + } + } + + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + String xmppJID = publishData[0]; + String xmppMessage = publishData[1]; + String xmppSubject = publishData[2]; + sendXMPPMessage(xmppJID, xmppMessage, xmppSubject); + } + + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + connectorServiceHandler.cancel(true); + closeConnection(); + if (log.isDebugEnabled()) { + log.warn("Unable to 'STOP' connection to XMPP server at: " + server + + " for user - " + xmppAdminUsername); + } + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("XMPP-Terminator: Thread Sleep Interrupt Exception for " + + DroneConstants.DEVICE_TYPE + " type.", e1); + } + } + } + }; + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage() throws TransportHandlerException { + + } + + @Override + public void processIncomingMessage(Message message, String... messageParams) throws TransportHandlerException { + + } + + @Override + public void publishDeviceData() throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(Message publishData) throws TransportHandlerException { + + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/trasformer/MessageTransformer.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/trasformer/MessageTransformer.java new file mode 100644 index 000000000..74d080771 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/trasformer/MessageTransformer.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.trasformer; + + +import org.apache.commons.collections4.queue.CircularFifoQueue; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.MessageConfig; + +import java.io.IOException; + + +public class MessageTransformer { + + private Log log = LogFactory.getLog(MessageTransformer.class); + private CircularFifoQueue sharedQueue; + + private String outboundMessageFormatForSimulator = "{\"quatanium_val\":[%f, %f, %f, %f]," + + "\"basicParam\":{\"velocity\":[%f, %f, %f], \"global_location\":[%f, %f, %f]},\"battery_level\":%f, \"device_type\":\"SIMULATOR\"}"; + private String outboundMessageFormatForIrisDrone = "{\"quatanium_val\":[%f, %f, %f]," + + "\"basicParam\":{\"velocity\":[%f, %f, %f], \"global_location\":[%f, %f, %f]},\"battery_level\":%f," + + "\"device_type\":\"IRIS_DRONE\"}"; + + public MessageTransformer(){ + sharedQueue = new CircularFifoQueue(DroneConstants.MAXIMUM_BUFFERE_SIZE_OF_SHARED_QUEUE); + } + + private void messageTranslaterForSimulator(JsonNode inbound_message){ + JsonNode node = inbound_message; + String outboundMessage; + try { + JsonNode velocity = node.get(MessageConfig.OUT_BASIC_PARAM_VAL).get(MessageConfig.OUT_BASIC_PARAM_VELOCITY); + JsonNode globalLocation = node.get(MessageConfig.OUT_BASIC_PARAM_VAL).get( + MessageConfig.OUT_BASIC_PARAM_GLOBAL_LOCATION); + JsonNode quataniumVals = node.get(MessageConfig.OUT_QUATANNIM_VAL); + JsonNode batteryLevel = node.get(MessageConfig.OUT_BATTERY_LEVEL); + outboundMessage = String.format(outboundMessageFormatForSimulator, sTd(quataniumVals.get(0)), + sTd(quataniumVals.get(1)), sTd(quataniumVals.get(2)), sTd(quataniumVals.get(0)), + sTd(velocity.get(0)), sTd(velocity.get(1)), sTd(velocity.get(2)), sTd(globalLocation.get(0)), + sTd(globalLocation.get(1)), sTd(globalLocation.get(2)), sTd(batteryLevel)); + sharedQueue.add(outboundMessage); + } catch (Exception e) { + log.error(e.getMessage()+",\n"+ e); + } + } + + private void messageTranslaterForIRISDrone(JsonNode inbound_message){ + JsonNode node = inbound_message; + String outboundMessage; + try { + + JsonNode velocity = node.get(MessageConfig.OUT_BASIC_PARAM_VAL).get(MessageConfig.OUT_BASIC_PARAM_VELOCITY); + JsonNode globalLocation = node.get(MessageConfig.OUT_BASIC_PARAM_VAL).get( + MessageConfig.OUT_BASIC_PARAM_GLOBAL_LOCATION); + JsonNode quataniumVals = node.get(MessageConfig.OUT_QUATANNIM_VAL); + JsonNode batteryLevel = node.get(MessageConfig.OUT_BATTERY_LEVEL); + outboundMessage = String.format(outboundMessageFormatForIrisDrone, sTd(quataniumVals.get(0)), + sTd(quataniumVals.get(1)), sTd(quataniumVals.get(2)), sTd(velocity.get(0)), + sTd(velocity.get(1)), sTd(velocity.get(2)), sTd(globalLocation.get(0)), + sTd(globalLocation.get(1)), sTd(globalLocation.get(2)), sTd(batteryLevel)); + sharedQueue.add(outboundMessage); + + }catch (Exception e) { + log.error(e.getMessage()+",\n"+ e); + } + } + + public void messageTranslater(String inbound_message){ + JsonNode actualMessage; + ObjectMapper objectMapper = new ObjectMapper(); + try { + actualMessage = objectMapper.readValue(inbound_message, JsonNode.class); + JsonNode deviceType = actualMessage.get(MessageConfig.IN_DEVICE_TYPE); + switch (deviceType.getTextValue()) { + case MessageConfig.IN_IRIS_DRONE: + messageTranslaterForIRISDrone(actualMessage); + break; + case MessageConfig.IN_SIMULATOR: + messageTranslaterForSimulator(actualMessage); + break; + default: + if(log.isDebugEnabled()){ + log.debug("Wrong message format"); + } + } + } catch (JsonProcessingException e) { + log.error("Incoming message might be corrupted, "+ e); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + + private double sTd(JsonNode s) + { + return Double.parseDouble(s.toString()); + } + + public String getMessage() { + try{ + if(sharedQueue.isEmpty() || sharedQueue == null){ + return ""; + } + return sharedQueue.remove(); + }catch(Exception e) { + log.error("There is no more messages to send or internal server error has been occurred, \n"+ e ); + return ""; + } + } + + public boolean isEmptyQueue(){ + return sharedQueue != null? sharedQueue.isEmpty():false; + } + +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/util/DroneAnalyzerServiceUtils.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/util/DroneAnalyzerServiceUtils.java new file mode 100644 index 000000000..0b6a3abff --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/controller/api/impl/util/DroneAnalyzerServiceUtils.java @@ -0,0 +1,96 @@ + +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.util; + +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api.impl.transport.DroneAnalyzerXMPPConnector; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.controller.DroneController; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; + +import java.io.File; + +public class DroneAnalyzerServiceUtils { + + private static final String SUPER_TENANT = "carbon.super"; + private static org.apache.commons.logging.Log log = LogFactory.getLog(DroneAnalyzerServiceUtils.class); + + public static void sendCommandViaXMPP(String deviceOwner, String deviceId, String resource, + String state, DroneAnalyzerXMPPConnector droneXMPPConnector) + throws DeviceManagementException, TransportHandlerException { + + String xmppServerDomain = XmppConfig.getInstance().getXmppEndpoint(); + int indexOfChar = xmppServerDomain.lastIndexOf(File.separator); + if (indexOfChar != -1) { + xmppServerDomain = xmppServerDomain.substring((indexOfChar + 1), xmppServerDomain.length()); + } + indexOfChar = xmppServerDomain.indexOf(":"); + if (indexOfChar != -1) { + xmppServerDomain = xmppServerDomain.substring(0, indexOfChar); + } + String clientToConnect = deviceId + "@" + xmppServerDomain + File.separator + deviceOwner; + String message = resource.replace("/", "") + ":" + state; + droneXMPPConnector.publishDeviceData(clientToConnect, message, "CONTROL-REQUEST"); + } + + public static boolean sendControlCommand(DroneController controller, String deviceId, String action, + double speed, double duration) + throws DeviceManagementException { + boolean controlState = false; + try{ + switch (action){ + case DroneConstants.TAKE_OFF: + controlState = controller.takeoff(); + break; + case DroneConstants.LAND: + controlState = controller.land(); + break; + case DroneConstants.BACK: + controlState = controller.back(speed, duration); + break; + case DroneConstants.CLOCK_WISE: + controlState = controller.clockwise(speed, duration); + break; + case DroneConstants.COUNTER_CLOCKWISE: + controlState = controller.conterClockwise(speed, duration); + break; + case DroneConstants.DOWN: + controlState = controller.down(speed, duration); + break; + case DroneConstants.FRONT: + controlState = controller.back(speed, duration); + break; + case DroneConstants.FORWARD: + controlState = controller.clockwise(speed, duration); + break; + case DroneConstants.UP: + controlState = controller.up(speed, duration); + break; + default: + log.error("Invalid command"); + break; + } + }catch(Exception e){ + log.error(e.getMessage()+ "\n"+ e); + } + return controlState; + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..cbaf62e25 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..2a9646df6 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,49 @@ + + + WSO2 IoT Server + WSO2 IoT Server + + 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 + /drone_analyzer/{version} + + + managed-api-application + drone_analyzer + + + managed-api-isSecured + true + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/pom.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/pom.xml new file mode 100644 index 000000000..34bf4cacd --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/pom.xml @@ -0,0 +1,261 @@ + + + + drone-analyzer-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api + war + WSO2 Carbon - IoT Server Drone Analyzer Manager API + http://maven.apache.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.springframework + spring-context + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + + commons-codec.wso2 + commons-codec + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.apache.commons + commons-collections4 + 4.0 + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.jwt.client.extension + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.application.extension + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + src/main/webapp/WEB-INF/web.xml + drone_analyzer_mgt + + + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/DroneManagerService.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/DroneManagerService.java new file mode 100644 index 000000000..149c9070e --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/DroneManagerService.java @@ -0,0 +1,319 @@ +/* + * 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.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api.impl; + +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey; +import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +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.controlqueue.xmpp.XmppAccount; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api.impl.util.APIUtil; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +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 org.wso2.carbon.device.mgt.jwt.client.extension.JWTClient; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClientManager; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.user.api.UserStoreException; + +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.Response; +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; + +public class DroneManagerService { + + private static org.apache.commons.logging.Log log = LogFactory.getLog(DroneManagerService.class); + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private static final String KEY_TYPE = "PRODUCTION"; + private static ApiApplicationKey apiApplicationKey; + + @Path("manager/device/register") + @POST + public boolean register(@QueryParam("deviceId") String deviceId, @QueryParam("name") String name) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DroneConstants.DEVICE_TYPE); + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return false; + } + 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(DroneConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); + device.setEnrolmentInfo(enrolmentInfo); + 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()); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, @Context HttpServletResponse response) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DroneConstants.DEVICE_TYPE); + 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()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @PUT + public boolean updateDevice(@PathParam("device_id") String deviceId, @QueryParam("name") String name, + @Context HttpServletResponse response) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DroneConstants.DEVICE_TYPE); + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(DroneConstants.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) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device getDevice(@PathParam("device_id") String deviceId) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DroneConstants.DEVICE_TYPE); + return APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/devices") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getDroneDevices() { + try { + List userDevices = APIUtil.getDeviceManagementService().getDevicesOfUser(APIUtil.getAuthenticatedUser()); + ArrayList userDevicesforDrone = new ArrayList<>(); + for (Device device : userDevices) { + if (device.getType().equals(DroneConstants.DEVICE_TYPE) && + device.getEnrolmentInfo().getStatus().equals( + EnrolmentInfo.Status.ACTIVE)) { + userDevicesforDrone.add(device); + } + } + return userDevicesforDrone.toArray(new Device[]{}); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + + + @Path("manager/device/{sketch_type}/download") + @GET + @Produces("application/octet-stream") + public Response downloadSketch(@QueryParam("deviceName") String deviceName, + @PathParam("sketch_type") String sketchType) { + try { + //create new device id + String deviceId = shortUUID(); + //create token + String token = UUID.randomUUID().toString(); + String refreshToken = UUID.randomUUID().toString(); + //adding registering data + boolean status = register(deviceId, deviceName); + if (!status) { + return Response.status(500).entity( + "Error occurred while registering the device with " + "id: " + deviceId + + " owner:" + APIUtil.getAuthenticatedUser()).build(); + + } + ZipUtil ziputil = new ZipUtil(); + ZipArchive zipFile; + try { + zipFile = ziputil.createZipFile(APIUtil.getAuthenticatedUser(), APIUtil.getTenantDomainOftheUser(), + sketchType, deviceId, deviceName, token, refreshToken); + } catch (DeviceManagementException ex) { + return Response.status(500).entity("Error occurred while creating zip file").build(); + } + Response.ResponseBuilder rb = Response.ok(zipFile.getZipFile()); + rb.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\""); + return rb.build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{sketch_type}/generate_link") + @GET + public Response generateSketchLink(@QueryParam("deviceName") String deviceName, + @PathParam("sketch_type") String sketchType) { + try { + ZipArchive zipFile = createDownloadFile(deviceName, sketchType); + Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId()); + return rb.build(); + } catch (IllegalArgumentException ex) { + return Response.status(400).entity(ex.getMessage()).build(); + } catch (DeviceManagementException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + private ZipArchive createDownloadFile(String deviceName, String sketchType) + throws DeviceManagementException, JWTClientException, APIManagerException, DeviceControllerException, + UserStoreException { + //create new device id + String deviceId = shortUUID(); + if (apiApplicationKey == null) { + String applicationUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration() + .getAdminUserName(); + APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); + String[] tags = {DroneConstants.DEVICE_TYPE}; + apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( + DroneConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); + } + JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + String scopes = "device_type_" + DroneConstants.DEVICE_TYPE + " device_" + deviceId; + AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), + apiApplicationKey.getConsumerSecret(), owner, scopes); + //create token + String accessToken = accessTokenInfo.getAccess_token(); + String refreshToken = accessTokenInfo.getRefresh_token(); + //adding registering data + XmppAccount newXmppAccount = new XmppAccount(); + newXmppAccount.setAccountName(APIUtil.getAuthenticatedUser() + "_" + deviceId); + newXmppAccount.setUsername(deviceId); + newXmppAccount.setPassword(accessToken); + newXmppAccount.setEmail(deviceId + "@wso2.com"); + XmppServerClient xmppServerClient = new XmppServerClient(); + xmppServerClient.initControlQueue(); + boolean status; + if (XmppConfig.getInstance().isEnabled()) { + status = xmppServerClient.createXMPPAccount(newXmppAccount); + if (!status) { + String msg = "XMPP Account was not created for device - " + deviceId + " of owner - " + + APIUtil.getAuthenticatedUser() + ".XMPP might have been disabled in org.wso2.carbon.device.mgt.iot.common.config.server.configs"; + log.warn(msg); + throw new DeviceManagementException(msg); + } + } + //Register the device with CDMF + status = register(deviceId, deviceName); + if (!status) { + String msg = "Error occurred while registering the device with " + "id: " + deviceId + + " owner:" + APIUtil.getAuthenticatedUser(); + throw new DeviceManagementException(msg); + } + ZipUtil ziputil = new ZipUtil(); + ZipArchive zipFile = ziputil.createZipFile(APIUtil.getAuthenticatedUser(), APIUtil.getTenantDomainOftheUser(), + sketchType, deviceId, deviceName, accessToken, refreshToken); + zipFile.setDeviceId(deviceId); + return zipFile; + } + + 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); + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/util/APIUtil.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/util/APIUtil.java new file mode 100644 index 000000000..e9980fa5a --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/manager/api/impl/util/APIUtil.java @@ -0,0 +1,55 @@ +package org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +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 { + + private static Log log = LogFactory.getLog(APIUtil.class); + + 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 getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String tenantDomain = threadLocalCarbonContext.getTenantDomain(); + return tenantDomain; + } + + 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static APIManagementProviderService getAPIManagementProviderService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + APIManagementProviderService apiManagementProviderService = + (APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null); + if (apiManagementProviderService == null) { + String msg = "API management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return apiManagementProviderService; + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..3a8849969 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..6947c58e1 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,62 @@ + + + WSO2 IoT Server + WSO2 IoT Server + + + 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 + /drone_analyzer/{version} + + + managed-api-application + drone_analyzer + + + managed-api-isSecured + true + + + + + + + + + + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/pom.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/pom.xml new file mode 100644 index 000000000..a3482fca4 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/pom.xml @@ -0,0 +1,108 @@ + + + + drone-analyzer-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin + bundle + WSO2 Carbon - IoT Server Drone Analyzer Device-Type Plugin + WSO2 Carbon - IoT Server Drone Analyzer Device-Type Plugin Implementation + http://maven.apache.org + + + UTF-8 + + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Impl Bundle + org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*;resolution:=optional, + javax.naming;resolution:=optional, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers;resolution:=optional, + javax.net;resolution:=optional, + javax.net.ssl;resolution:=optional, + org.w3c.dom;resolution:=optional, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + org.wso2.carbon.device.mgt.extensions.feature.mgt.*, + org.wso2.carbon.utils.* + + + !org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.internal, + org.wso2.carbon.device.mgt.iot.droneanalyzer.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 + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.utils + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/DroneConstants.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/DroneConstants.java new file mode 100644 index 000000000..03b950f10 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/DroneConstants.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants; + +public class DroneConstants { + + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "DRONE_DEVICE_ID"; + public final static String MESSAGE_RESOURCE = "drone_current_status"; + public static final String DEVICE_TYPE = "drone_analyzer"; + public static final int MINIMUM_TIME_DURATION = 150; + public static final int MAXIMUM_BUFFERE_SIZE_OF_SHARED_QUEUE = 10; + public static final String DEVICE_ID = "drone_type1"; + public final static String TAKE_OFF = "takeoff"; + public final static String LAND = "land"; + public final static String UP = "up"; + public final static String DOWN = "down"; + public final static String BACK = "back"; + public final static String FORWARD = "forward"; + public final static String FRONT = "front"; + public final static String CLOCK_WISE = "clockwise"; + public final static String COUNTER_CLOCKWISE = "counterClockwise"; + public static final String DATA_SOURCE_NAME = "jdbc/DroneAnalyzerDM_DB"; + +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/MessageConfig.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/MessageConfig.java new file mode 100644 index 000000000..d6d64b359 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/constants/MessageConfig.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants; + +public class MessageConfig { + + public static final String IN_QUATANNIM_VAL = "quatanium_val"; + public static final String IN_DEVICE_TYPE = "device_type"; + public static final String IN_IRIS_DRONE = "IRIS_DRONE"; + public static final String IN_SIMULATOR = "SIMULATOR"; + public static final String OUT_QUATANNIM_VAL = "quatanium_val"; + public static final String IN_ACCELETOMETER_VAL = "accelerometer"; + public static final String OUT_ACCELETOMETER_VAL = "accelerometer"; + public static final String IN_GYROSCOPE_VAL = "gyroscope"; + public static final String OUT_GYROSCOPE_VAL = "gyroscope"; + public static final String IN_MAGNETOMETER_VAL = "magnetometer"; + public static final String OUT_MAGNETOMETER_VAL = "magnetometer"; + public static final String IN_BASIC_PARAM_VAL = "basicParam"; + public static final String OUT_BASIC_PARAM_VAL = "basicParam"; + public static final String OUT_BASIC_PARAM_VELOCITY = "velocity"; + public static final String OUT_BASIC_PARAM_GLOBAL_LOCATION = "global_location"; + public static final String OUT_BATTERY_LEVEL = "battery_level"; + +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/DroneController.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/DroneController.java new file mode 100644 index 000000000..0bf48f4ea --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/DroneController.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.controller; + +public interface DroneController { + boolean takeoff(); + boolean land(); + boolean up(double speed, double duration); + boolean down(double speed, double duration); + boolean left(double speed, double duration); + boolean right(double speed, double duration); + boolean front(double speed, double duration); + boolean back(double speed, double duration); + boolean clockwise(double speed, double duration); + boolean conterClockwise(double speed, double duration); +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/impl/DroneControllerImpl.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/impl/DroneControllerImpl.java new file mode 100644 index 000000000..b9fd5e073 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/controller/impl/DroneControllerImpl.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.controller.impl; + +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.controller.DroneController; + +public class DroneControllerImpl implements DroneController{ + + @Override + public boolean takeoff() { + return false; + } + + @Override + public boolean land() { + return false; + } + + @Override + public boolean up(double speed, double duration) { + return false; + } + + @Override + public boolean down(double speed, double duration) { + return false; + } + + @Override + public boolean left(double speed, double duration) { + return false; + } + + @Override + public boolean right(double speed, double duration) { + return false; + } + + @Override + public boolean front(double speed, double duration) { + return false; + } + + @Override + public boolean back(double speed, double duration) { + return false; + } + + @Override + public boolean clockwise(double speed, double duration) { + return false; + } + + @Override + public boolean conterClockwise(double speed, double duration) { + return false; + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/exception/DroneAnalyzerDeviceMgtPluginException.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/exception/DroneAnalyzerDeviceMgtPluginException.java new file mode 100644 index 000000000..e3d118ef6 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/exception/DroneAnalyzerDeviceMgtPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.exception; + + +public class DroneAnalyzerDeviceMgtPluginException extends Exception{ + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public DroneAnalyzerDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public DroneAnalyzerDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public DroneAnalyzerDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public DroneAnalyzerDeviceMgtPluginException() { + super(); + } + + public DroneAnalyzerDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManager.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManager.java new file mode 100644 index 000000000..a88018885 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManager.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.*; +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 org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.exception.DroneAnalyzerDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.dao.DroneAnalyzerDAO; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.feature.DroneAnalyzerFeatureManager; +import java.util.List; + +/** + * This represents the Drone Analyzer service implementation of DeviceManagerService. + */ +public class DroneAnalyzerManager implements DeviceManager { + + private static final DroneAnalyzerDAO droneAnalyzerDAO = new DroneAnalyzerDAO(); + private static final Log log = LogFactory.getLog(DroneAnalyzerManager.class); + private FeatureManager droneFeatureManager = new DroneAnalyzerFeatureManager(); + @Override + public FeatureManager getFeatureManager() { + return droneFeatureManager; + } + + @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 drone device : " + device.getDeviceIdentifier()); + } + DroneAnalyzerDAO.beginTransaction(); + status = droneAnalyzerDAO.getDeviceDAO().addDevice(device); + DroneAnalyzerDAO.commitTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + try { + DroneAnalyzerDAO.rollbackTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the drone 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 Virtual Firealarm device enrollment data"); + } + DroneAnalyzerDAO.beginTransaction(); + status = droneAnalyzerDAO.getDeviceDAO().updateDevice(device); + DroneAnalyzerDAO.commitTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + try { + DroneAnalyzerDAO.rollbackTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException 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 drone 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 drone device : " + deviceId); + } + DroneAnalyzerDAO.beginTransaction(); + status = droneAnalyzerDAO.getDeviceDAO().deleteIotDevice(deviceId.getId()); + DroneAnalyzerDAO.commitTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + try { + DroneAnalyzerDAO.rollbackTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException 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 drone 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 Drone device : " + deviceId.getId()); + } + Device iotDevice = droneAnalyzerDAO.getDeviceDAO().getDevice(deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (DroneAnalyzerDeviceMgtPluginException e) { + String msg = "Error while checking the enrollment status of Drone 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 Drone device : " + deviceId.getId()); + } + device = droneAnalyzerDAO.getDeviceDAO().getDevice(deviceId.getId()); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + String msg = "Error while fetching the Drone 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 updateDeviceInfo(DeviceIdentifier deviceIdentifier, Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug( + "updating the details of Drone device : " + deviceIdentifier); + } + DroneAnalyzerDAO.beginTransaction(); + status = droneAnalyzerDAO.getDeviceDAO().updateDevice(device); + DroneAnalyzerDAO.commitTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + try { + DroneAnalyzerDAO.rollbackTransaction(); + } catch (DroneAnalyzerDeviceMgtPluginException 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 Drone device : " + deviceIdentifier; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public List getAllDevices() throws DeviceManagementException { + List devices = null; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Drone devices"); + } + devices = droneAnalyzerDAO.getDeviceDAO().getAllDevices(); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + String msg = "Error while fetching all Drone devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + + @Override + public boolean requireDeviceAuthorization() { + return true; + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManagerService.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManagerService.java new file mode 100644 index 000000000..5af1a9008 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/DroneAnalyzerManagerService.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; + +import java.util.List; + + +public class DroneAnalyzerManagerService implements DeviceManagementService { + private DeviceManager deviceManager; + @Override + public String getType() { + return DroneConstants.DEVICE_TYPE; + } + + @Override + public void init() throws DeviceManagementException { + this.deviceManager = new DroneAnalyzerManager(); + } + + @Override + public DeviceManager getDeviceManager() { + return deviceManager; + } + + @Override + public ApplicationManager getApplicationManager() { + return null; + } + + @Override + public void notifyOperationToDevices(Operation operation, List list) + throws DeviceManagementException { + + } + + @Override + public Application[] getApplications(String s, int i, int i1) throws ApplicationManagementException { + return new Application[0]; + } + + @Override + public void updateApplicationStatus(DeviceIdentifier deviceIdentifier, Application application, String s) + throws ApplicationManagementException { + + } + + @Override + public String getApplicationStatus(DeviceIdentifier deviceIdentifier, Application application) + throws ApplicationManagementException { + return null; + } + + @Override + public void installApplicationForDevices(Operation operation, List list) + throws ApplicationManagementException { + + } + + @Override + public void installApplicationForUsers(Operation operation, List list) + throws ApplicationManagementException { + + } + + @Override + public void installApplicationForUserRoles(Operation operation, List list) + throws ApplicationManagementException { + + } + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/DroneAnalyzerDAO.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/DroneAnalyzerDAO.java new file mode 100644 index 000000000..26896bc77 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/DroneAnalyzerDAO.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.exception.DroneAnalyzerDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.dao.impl.DroneAnalyzerDeviceDAOImpl; +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 DroneAnalyzerDAO { + + private static final Log log = LogFactory.getLog(DroneAnalyzerDAO.class); + static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal(); + + public DroneAnalyzerDAO() { + initDroneAnalyzerDAO(); + } + + public static void initDroneAnalyzerDAO() { + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(DroneConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + DroneConstants.DATA_SOURCE_NAME); + } + } + + public DroneAnalyzerDeviceDAOImpl getDeviceDAO() { + return new DroneAnalyzerDeviceDAOImpl(); + } + + public static void beginTransaction() throws DroneAnalyzerDeviceMgtPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new DroneAnalyzerDeviceMgtPluginException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws DroneAnalyzerDeviceMgtPluginException { + + if (currentConnection != null && currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new DroneAnalyzerDeviceMgtPluginException("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws DroneAnalyzerDeviceMgtPluginException { + 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 DroneAnalyzerDeviceMgtPluginException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws DroneAnalyzerDeviceMgtPluginException { + 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 DroneAnalyzerDeviceMgtPluginException { + 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 DroneAnalyzerDeviceMgtPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/impl/DroneAnalyzerDeviceDAOImpl.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/impl/DroneAnalyzerDeviceDAOImpl.java new file mode 100644 index 000000000..35ce12860 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/dao/impl/DroneAnalyzerDeviceDAOImpl.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.exception.DroneAnalyzerDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.dao.DroneAnalyzerDAO; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.util.DroneAnalyzerUtils; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +/** + * Implements CRUD for drone analyzer. + */ +public class DroneAnalyzerDeviceDAOImpl { + + private static final Log log = LogFactory.getLog(DroneAnalyzerDeviceDAOImpl.class); + + public Device getDevice(String deviceId) throws DroneAnalyzerDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + Device device = null; + ResultSet resultSet = null; + try { + conn = DroneAnalyzerDAO.getConnection(); + if(conn == null){ + log.error("Database connection hasn't been created"); + } + String selectDBQuery = + "SELECT DRONE_DEVICE_ID, DEVICE_NAME FROM DRONE_DEVICE WHERE DRONE_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, deviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + device = new Device(); + if (log.isDebugEnabled()) { + log.debug("Drone device " + deviceId + " data has been fetched from " + + "Drone database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching drone device : '" + deviceId + "'"; + log.error(msg, e); + throw new DroneAnalyzerDeviceMgtPluginException(msg, e); + } finally { + DroneAnalyzerUtils.cleanupResources(stmt, resultSet); + DroneAnalyzerDAO.closeConnection(); + } + return device; + } + + public boolean addDevice(Device device) throws DroneAnalyzerDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DroneAnalyzerDAO.getConnection(); + String createDBQuery = + "INSERT INTO DRONE_DEVICE(DRONE_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, device.getDeviceIdentifier()); + stmt.setString(2, device.getName()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("drone device " + device.getDeviceIdentifier() + " data has been" + + " added to the drone database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the drone device '" + + device.getDeviceIdentifier() + "' to the drone db."; + log.error(msg, e); + throw new DroneAnalyzerDeviceMgtPluginException(msg, e); + } finally { + DroneAnalyzerUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device device) throws DroneAnalyzerDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DroneAnalyzerDAO.getConnection(); + String updateDBQuery = + "UPDATE DRONE_DEVICE SET DEVICE_NAME = ? WHERE DRONE_DEVICE_ID = ?"; + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, device.getName()); + stmt.setString(2, device.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Drone device " + device.getDeviceIdentifier() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Drone device '" + device.getDeviceIdentifier() + "' data."; + log.error(msg, e); + throw new DroneAnalyzerDeviceMgtPluginException(msg, e); + } finally { + DroneAnalyzerUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteIotDevice(String iotDeviceId) throws DroneAnalyzerDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DroneAnalyzerDAO.getConnection(); + System.out.println("delete device "); + String deleteDBQuery = + "DELETE FROM DRONE_DEVICE WHERE DRONE_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, iotDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Drone device " + iotDeviceId + " data has deleted" + + " from the drone database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting drone device " + iotDeviceId; + log.error(msg, e); + throw new DroneAnalyzerDeviceMgtPluginException(msg, e); + } finally { + DroneAnalyzerUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws DroneAnalyzerDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device iotDevice; + List iotDevices = new ArrayList(); + try { + conn = DroneAnalyzerDAO.getConnection(); + String selectDBQuery = + "SELECT DRONE_DEVICE_ID, DEVICE_NAME " + + "FROM DRONE_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + iotDevice = new Device(); + iotDevice.setDeviceIdentifier(resultSet.getString(DroneConstants.DEVICE_PLUGIN_DEVICE_ID)); + iotDevice.setName(resultSet.getString(DroneConstants.DEVICE_PLUGIN_DEVICE_NAME)); + } + if (log.isDebugEnabled()) { + log.debug("All drone device details have fetched from drone database."); + } + return iotDevices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all drone device data'"; + log.error(msg, e); + throw new DroneAnalyzerDeviceMgtPluginException(msg, e); + } finally { + DroneAnalyzerUtils.cleanupResources(stmt, resultSet); + DroneAnalyzerDAO.closeConnection(); + } + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/feature/DroneAnalyzerFeatureManager.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/feature/DroneAnalyzerFeatureManager.java new file mode 100644 index 000000000..6a9127cfd --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/feature/DroneAnalyzerFeatureManager.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.feature; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; + +import java.util.List; + +public class DroneAnalyzerFeatureManager implements FeatureManager { + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + return false; + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + return false; + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeature(DroneConstants.DEVICE_TYPE, name); + } + + @Override + public List getFeatures() throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeatures(DroneConstants.DEVICE_TYPE); + } + + @Override + public boolean removeFeature(String name) throws DeviceManagementException { + return false; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + return false; + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DeviceSchemaInitializer.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DeviceSchemaInitializer.java new file mode 100644 index 000000000..e96b4e0b1 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DeviceSchemaInitializer.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * Provides methods for initializing the database script. + */ +public class DeviceSchemaInitializer extends DatabaseCreator{ + + private static final Log log = LogFactory.getLog(DeviceSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + + File.separator + "cdm" + File.separator + "plugins" + File.separator; + + public DeviceSchemaInitializer(DataSource dataSource) { + super(dataSource); + } + + @Override + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptName); + } + return setupSQLScriptBaseLocation.replaceFirst("DBTYPE", databaseType) + scriptName; + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DroneAnalyzerUtils.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DroneAnalyzerUtils.java new file mode 100644 index 000000000..e65c0f0c4 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/impl/util/DroneAnalyzerUtils.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.constants.DroneConstants; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.exception.DroneAnalyzerDeviceMgtPluginException; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +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 Drone Analyzer plugin. + */ +public class DroneAnalyzerUtils { + private static Log log = LogFactory.getLog(DroneAnalyzerUtils.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); + } + + /** + * Creates the device management schema. + */ + public static void setupDeviceManagementSchema() throws DroneAnalyzerDeviceMgtPluginException { + try { + Context ctx = new InitialContext(); + DataSource dataSource = (DataSource) ctx.lookup(DroneConstants.DATA_SOURCE_NAME); + DeviceSchemaInitializer initializer = + new DeviceSchemaInitializer(dataSource); + log.info("Initializing device management repository database schema"); + initializer.createRegistryDatabase(); + + } catch (NamingException e) { + log.error("Error while looking up the data source: " + DroneConstants.DATA_SOURCE_NAME); + } catch (Exception e) { + throw new DroneAnalyzerDeviceMgtPluginException("Error occurred while initializing Iot Device " + + "Management database schema", e); + } + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/internal/DroneAnalyzerManagementServiceComponent.java b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/internal/DroneAnalyzerManagementServiceComponent.java new file mode 100644 index 000000000..01e648773 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin/src/main/java/org/wso2/carbon/device/mgt/iot/droneanalyzer/plugin/internal/DroneAnalyzerManagementServiceComponent.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.exception.DroneAnalyzerDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.DroneAnalyzerManagerService; +import org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.impl.util.DroneAnalyzerUtils; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin.internal + * .DroneAnalyzerManagementServiceComponent" + * immediate="true" + */ +public class DroneAnalyzerManagementServiceComponent { + private ServiceRegistration firealarmServiceRegRef; + + private static final Log log = LogFactory.getLog( + DroneAnalyzerManagementServiceComponent.class); + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Drone Analyzer Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + firealarmServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + new DroneAnalyzerManagerService(), null); + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug( + "-Dsetup is enabled. Iot Device management repository schema initialization is about " + + "to begin"); + } + try { + DroneAnalyzerUtils.setupDeviceManagementSchema(); + } catch (DroneAnalyzerDeviceMgtPluginException e) { + log.error("Exception occurred while initializing device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug( + "Drone Analyzer Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Drone Analyzer Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Drone Analyzer Device Management Service Component"); + } + try { + if (firealarmServiceRegRef != null) { + firealarmServiceRegRef.unregister(); + } + if (log.isDebugEnabled()) { + log.debug("Drone Analyzer Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error( + "Error occurred while de-activating Drone Analyzer Device Management bundle",e); + } + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/pom.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/pom.xml new file mode 100644 index 000000000..5b7426489 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + drone-analyzer-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.droneanalyzer.ui + WSO2 Carbon - IoT Server Drone Analyzer UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/assembly/src.xml b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.hbs b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.hbs new file mode 100644 index 000000000..1d32daed4 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.hbs @@ -0,0 +1,52 @@ +{{#zone "device-thumbnail"}} + +{{/zone}} +{{#zone "device-opetations"}} +
      + {{unit "iot.unit.device.operation-bar" device=device}} +
      +
      +
      Device Statistics
      + {{unit "iot.unit.device.droneanalyzer.statistics" device=device}} +
      + +{{/zone}} +{{#zone "device-detail-properties"}} +
      +
      + +
      +
      + +
      +
      +
      Operations Log
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      +
      +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.js new file mode 100644 index 000000000..1fcbacc5b --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.js @@ -0,0 +1,34 @@ +/* + * 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"); + + 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") { + return {"device": device}; + } else { + response.sendError(404, "Device Id " + deviceId + "of type " + deviceType + " cannot be found!"); + exit(); + } + } +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.json b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/public/images/drone-icon.png b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.device-view/public/images/drone-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7744ff42d16a9761778c98749aa50ea93e5cb4 GIT binary patch literal 46940 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

      J&TxbYUA`g6Fvzap%(O*Fj*K~ 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

      J&TxbYUA`g6Fvzap%(O*Fj*K~ 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/images/drone-icon.png b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/images/drone-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7744ff42d16a9761778c98749aa50ea93e5cb4 GIT binary patch literal 46940 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

      J&TxbYUA`g6Fvzap%(O*Fj*K~ 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/download.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/download.js new file mode 100644 index 000000000..0c22e5099 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/download.js @@ -0,0 +1,184 @@ +/* + * 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. + */ + +var modalPopup = ".wr-modalpopup"; +var modalPopupContainer = modalPopup + " .modalpopup-container"; +var modalPopupContent = modalPopup + " .modalpopup-content"; +var body = "body"; + +/* + * set popup maximum height function. + */ +function setPopupMaxHeight() { + $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30))); + $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2))); +} + +/* + * show popup function. + */ +function showPopup() { + $(modalPopup).show(); + setPopupMaxHeight(); + $('#downloadForm').validate({ + rules: { + deviceName: { + minlength: 4, + required: true + } + }, + highlight: function (element) { + $(element).closest('.control-group').removeClass('success').addClass('error'); + }, + success: function (element) { + $(element).closest('.control-group').removeClass('error').addClass('success'); + $('label[for=deviceName]').remove(); + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); +} + +/* + * hide popup function. + */ +function hidePopup() { + $('label[for=deviceName]').remove(); + $('.control-group').removeClass('success').removeClass('error'); + $(modalPopupContent).html(''); + $(modalPopup).hide(); +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + attachEvents(); +}); + +function attachEvents() { + /** + * Following click function would execute + * when a user clicks on "Download" link + * on Device Management page in WSO2 DC Console. + */ + $("a.download-link").click(function () { + var sketchType = $(this).data("sketchtype"); + var deviceType = $(this).data("devicetype"); + var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link"; + var payload = {"sketchType": sketchType, "deviceType": deviceType}; + $(modalPopupContent).html($('#download-device-modal-content').html()); + showPopup(); + var deviceName; + $("a#download-device-download-link").click(function () { + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + $('label[for=deviceName]').remove(); + if (deviceName && deviceName.length >= 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 deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/; + if (deviceName && deviceNameFormat.test(deviceName)) { + $('#downloadForm').submit(); + hidePopup(); + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + showPopup(); + setTimeout(function () { + hidePopup(); + }, 1000); + }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 == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showPopup(); + } else 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/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/jquery.validate.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.hbs b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.hbs new file mode 100644 index 000000000..d02b3354f --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.hbs @@ -0,0 +1,315 @@ +

      +
      + +
      +
      + +
      +
      +

      What it Does

      +
      +

      Connect an + [IRIS+] Drone to + WSO2 IoT Server and visualize statistics. +

      +
      + +

      What You Need

      +
      +
        +
      • + ITEM 01 +    IRIS+ Drone. +
      • +
      • + ITEM 02 +    USB to Micro USB cable or Telemetry Radio receiver. +
      • +
      • + STEP 03 +    Proceed to [Prepare] section. +
      +
      + View API
        + + Download Agent + +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +

      +
      +
      +

      Prepare

      +
      +
        +
      • + 01 +    Connect your IRIS+ Drone to your computer using either USB to Micro + USB cable or Telemetry Radio receiver. +
      • +
      • + 02 +    Click on [Download Agent] button above to get IRIS+ Drone agent. +
      • +
      • + 03 +    Once you have downloaded the agent please run + "[startService.sh]" script with root privileges. +
      • +
      • + 04 +    Then you will be prompted to enter time interval (in seconds) between + successive Data-Pushes to the XMPP server, connection target and communication speed. So + below table will help you to find what is the correct connection target and + communication speed. +
      • +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        +
        CONNECTION-TYPE
        +
        +
        CONNECTION-STRING
        +
        Linux computer connected to the vehicle via USB e.g. /dev/ttyUSB0
        Linux computer connected to the drone via Serial port e.g. /dev/ttyAMA0 (also set baud=57600)
        OSX computer connected to the drone via USBe.g. dev/cu.usbmodem1
        Windows computer connected to the drone via USB (in this case on COM14)e.g. com14
        Windows computer connected to the drone using a 3DR Telemetry Radio on + COM14 + e.g. com14 (also set baud=57600)
        +
        +
      +
      +
      +
      +

      IRIS+ Drone Connected to a computer

      +
      +

      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 view stats which are published by + the device. +
      • +
      +
      +

      Click on the image to zoom

      +
      + + + +
      +
      + +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + {{js "/js/jquery.validate.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.json b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.drone_analyzer.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/css/main-app.css b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/css/main-app.css new file mode 100644 index 000000000..9f7521295 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/css/main-app.css @@ -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. + */ +.box { + margin-top: 10px; + margin-bottom: 10px; +} + +.box-inner { + border: 1px solid #DEDEDE; + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + box-shadow: 0 0 10px rgba(189, 189, 189, 0.4); + -webkit-box-shadow: 0 0 10px rgba(189, 189, 189, 0.4); + -moz-box-shadow: 0 0 10px rgba(189, 189, 189, 0.4); +} + +.box-header { + border: none; + padding-top: 5px; + border-bottom: 1px solid #DEDEDE; + border-radius: 3px 3px 0 0; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + height: 35px; + min-height: 35px !important; + margin-bottom: 0; + font-weight: bold; + font-size: 16px; + background: -moz-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgba(0, 0, 0, 0.1))); + background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%); + background: -o-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%); + background: -ms-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%); + background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffffff', endColorstr='#1a000000', GradientType=0); + +} + +.box-header h2 { + font-size: 15px; + width: auto; + clear: none; + float: left; + line-height: 25px; + white-space: nowrap; + font-weight: bold; + margin-top: 0; + margin-bottom: 0; +} + +.box-header h3 { + font-size: 13px; + width: auto; + clear: none; + float: left; + line-height: 25px; + white-space: nowrap; +} + +.box-header h2 > i { + margin-top: 1px; +} + +.box-icon { + float: right; +} + +.box-icon a { + clear: none; + float: left; + margin: 0 2px; + height: 20px; + width: 5px; + margin-top: 1px; +} + +.box-icon a i { + margin-left: -6px; + top: -1px; +} + +.box-content { + padding: 10px; +} + +.btn-round { + border-radius: 40px; + -webkit-border-radius: 40px; + -moz-border-radius: 40px; + font-size: 12px; + padding-top: 4px; +} + +.navbar-brand { + font-family: 'Shojumaru', cursive, Arial, serif; + letter-spacing: 2px; + text-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5); + width: 183px; + font-size: 17px; +} + +.navbar-brand img { + float: left; + height: 20px; + width: 20px; + margin-right: 5px; +} + +.navbar-brand span { + float: left; +} + +.navbar-search { + margin-left: 10px; + margin-top: 7px; +} + +.navbar-inner { + padding-top: 5px; + padding-bottom: 5px; + line-height: 30px; + height: 60px; +} + +.navbar-inner .btn-group { + margin: 7px 5px 0 5px; +} + +.bs-icons li { + list-style: none; +} + +.box-content .nav-tabs { + margin-right: -10px; + margin-left: -10px; +} + +.box-content.buttons { + min-height: 297px; +} + +.sidebar-nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.navbar { + border-radius: 0; +} +.circle { + background: none repeat scroll 0 0 #191919; + border-radius: 50px; + height: 50px; + padding: 10px; + width: 50px; + color: #fff; +} + +.padding-top-double { + padding-top: 20px; +} +.padding-double { + padding: 20px; +} +.grey { + color: #333; +} +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #7f7f7f; + margin: 1em 0; + padding: 0; + opacity: 0.2; +} +.light-grey { + color: #7c7c7c; +} +.uppercase { + text-transform: uppercase; +} +.grey-bg { + background-color: #f6f4f4; +} + +path { + stroke: black; + stroke-width: 2; + fill: none; +} + +.axis path, .axis line { + fill: none; + stroke: #ccc; + stroke-width: 2; + shape-rendering: crispEdges; +} diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/background_drone.png b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/background_drone.png new file mode 100644 index 0000000000000000000000000000000000000000..c3ce7dc40d87da479b11193a13a91c2f68363547 GIT binary patch literal 26787 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/pitch_drone.png b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/images/drone_position_controller/pitch_drone.png new file mode 100644 index 0000000000000000000000000000000000000000..84afb8f1888ebec0dbd5cb4b8c3bde86c3bc05de GIT binary patch literal 20046 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 0 ) { + + this.dispatchEvent( changeEvent ); + + lastPosition.copy( this.object.position ); + + } + + }; + + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function onMouseDown( event ) { + + if ( scope.enabled === false ) { return; } + event.preventDefault(); + + if ( event.button === 0 ) { + if ( scope.noRotate === true ) { return; } + + state = STATE.ROTATE; + + rotateStart.set( event.clientX, event.clientY ); + + } else if ( event.button === 1 ) { + if ( scope.noZoom === true ) { return; } + + state = STATE.DOLLY; + + dollyStart.set( event.clientX, event.clientY ); + + } else if ( event.button === 2 ) { + if ( scope.noPan === true ) { return; } + + state = STATE.PAN; + + panStart.set( event.clientX, event.clientY ); + + } + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) { return; } + + event.preventDefault(); + + if ( state === STATE.ROTATE ) { + if ( scope.noRotate === true ) { return; } + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + } else if ( state === STATE.DOLLY ) { + if ( scope.noZoom === true ) { return; } + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyIn(); + + } else { + + scope.dollyOut(); + + } + + dollyStart.copy( dollyEnd ); + + } else if ( state === STATE.PAN ) { + if ( scope.noPan === true ) { return; } + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta ); + + panStart.copy( panEnd ); + + } + + } + + function onMouseUp( /* event */ ) { + + if ( scope.enabled === false ) { return; } + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + // this is needed when the program is inside an iframe + // to prevent scrolling the whole page + event.preventDefault(); + if ( scope.enabled === false ) { return; } + if ( scope.noZoom === true ) { return; } + + var delta = 0; + + if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta; + + } else if ( event.detail ) { // Firefox + + delta = - event.detail; + + } + + if ( delta > 0 ) { + + scope.dollyOut(); + + } else { + + scope.dollyIn(); + + } + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false ) { return; } + if ( scope.noKeys === true ) { return; } + if ( scope.noPan === true ) { return; } + + // pan a pixel - I guess for precise positioning? + switch ( event.keyCode ) { + + case scope.keys.UP: + scope.pan( new THREE.Vector2( 0, 1 ) ); + break; + case scope.keys.BOTTOM: + scope.pan( new THREE.Vector2( 0, -1 ) ); + break; + case scope.keys.LEFT: + scope.pan( new THREE.Vector2( 1, 0 ) ); + break; + case scope.keys.RIGHT: + scope.pan( new THREE.Vector2( -1, 0 ) ); + break; + } + + } + + function touchstart( event ) { + + if ( scope.enabled === false ) { return; } + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + if ( scope.noRotate === true ) { return; } + + state = STATE.TOUCH_ROTATE; + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: // two-fingered touch: dolly + if ( scope.noZoom === true ) { return; } + + state = STATE.TOUCH_DOLLY; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + break; + + case 3: // three-fingered touch: pan + if ( scope.noPan === true ) { return; } + + state = STATE.TOUCH_PAN; + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + state = STATE.NONE; + + } + } + + function touchmove( event ) { + + if ( scope.enabled === false ) { return; } + + event.preventDefault(); + event.stopPropagation(); + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + if ( scope.noRotate === true ) { return; } + if ( state !== STATE.TOUCH_ROTATE ) { return; } + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + scope.rotateLeft( 2 * Math.PI * rotateDelta.x / scope.domElement.width * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + scope.rotateUp( 2 * Math.PI * rotateDelta.y / scope.domElement.height * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + break; + + case 2: // two-fingered touch: dolly + if ( scope.noZoom === true ) { return; } + if ( state !== STATE.TOUCH_DOLLY ) { return; } + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + scope.dollyOut(); + + } else { + + scope.dollyIn(); + + } + + dollyStart.copy( dollyEnd ); + break; + + case 3: // three-fingered touch: pan + if ( scope.noPan === true ) { return; } + if ( state !== STATE.TOUCH_PAN ) { return; } + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + panDelta.subVectors( panEnd, panStart ); + + scope.pan( panDelta ); + + panStart.copy( panEnd ); + break; + + default: + state = STATE.NONE; + + } + + } + + function touchend( /* event */ ) { + + if ( scope.enabled === false ) { return; } + + state = STATE.NONE; + } + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); + this.domElement.addEventListener( 'mousedown', onMouseDown, false ); + this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.addEventListener( 'keydown', onKeyDown, false ); + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + +}; diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/three.min.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/three.min.js new file mode 100644 index 000000000..f088be7af --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/3dobject_controller/three.min.js @@ -0,0 +1,724 @@ +/* + * 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. + */ + +// three.js - http://github.com/mrdoob/three.js +'use strict';var THREE=THREE||{REVISION:"56"};self.console=self.console||{info:function(){},log:function(){},debug:function(){},warn:function(){},error:function(){}};self.Int32Array=self.Int32Array||Array;self.Float32Array=self.Float32Array||Array;String.prototype.trim=String.prototype.trim||function(){return this.replace(/^\s+|\s+$/g,"")}; +THREE.extend=function(a,b){if(Object.keys)for(var c=Object.keys(b),d=0,e=c.length;d>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSV:function(a,b,c){console.log("DEPRECATED: Color's .setHSV() will be removed. Use .setHSL( h, s, l ) instead.");return this.setHSL(a,b*c/(1>(a=(2-b)*c)?a:2-a),a/2)},setHSL:function(a, +b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1c?b:c<2/3?a+6*(b-a)*(2/3-c):a},b=0.5>=c?c*(1+b):c+b-c*b,c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+),(\d+),(\d+)\)$/i.test(a))return a=/^rgb\((\d+),(\d+),(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.test(a))return a= +/^rgb\((\d+)\%,(\d+)\%,(\d+)\%\)$/i.exec(a),this.r=Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]), +this},copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255* +this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(){var a={h:0,s:0,l:0};return function(){var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var i=e-f,f=0.5>=h?i/(e+f):i/(2-e-f);switch(e){case b:g=(c-d)/i+(cf&&c>b?(c=2*Math.sqrt(1+c-f-b),this.w=(i-g)/c,this.x=0.25*c,this.y=(a+e)/c,this.z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this.w=(d-h)/c,this.x=(a+e)/c,this.y=0.25*c,this.z=(g+i)/c):(c=2*Math.sqrt(1+b-c-f),this.w=(e-a)/c,this.x=(d+h)/c,this.y=(g+i)/c,this.z=0.25*c);return this},inverse:function(){this.conjugate().normalize(); +return this},conjugate:function(){this.x*=-1;this.y*=-1;this.z*=-1;return this},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},normalize:function(){var a=this.length();0===a?(this.z=this.y=this.x=0,this.w=1):(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a);return this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."), +this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a.x,d=a.y,e=a.z,f=a.w,g=b.x,h=b.y,i=b.z,k=b.w;this.x=c*k+f*g+d*i-e*h;this.y=d*k+f*h+e*g-c*i;this.z=e*k+f*i+c*h-d*g;this.w=f*k-c*g-d*h-e*i;return this},multiplyVector3:function(a){console.warn("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)},slerp:function(a,b){var c=this.x,d=this.y,e=this.z, +f=this.w,g=f*a.w+c*a.x+d*a.y+e*a.z;0>g?(this.w=-a.w,this.x=-a.x,this.y=-a.y,this.z=-a.z,g=-g):this.copy(a);if(1<=g)return this.w=f,this.x=c,this.y=d,this.z=e,this;var h=Math.acos(g),i=Math.sqrt(1-g*g);if(0.001>Math.abs(i))return this.w=0.5*(f+this.w),this.x=0.5*(c+this.x),this.y=0.5*(d+this.y),this.z=0.5*(e+this.z),this;g=Math.sin((1-b)*h)/i;h=Math.sin(b*h)/i;this.w=f*g+this.w*h;this.x=c*g+this.x*h;this.y=d*g+this.y*h;this.z=e*g+this.z*h;return this},equals:function(a){return a.x===this.x&&a.y=== +this.y&&a.z===this.z&&a.w===this.w},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)}});THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; +THREE.extend(THREE.Vector2.prototype,{set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!== +b)return console.warn("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, +subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a):this.set(0,0);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);return this},negate:function(){return this.multiplyScalar(-1)}, +dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)* +b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},toArray:function(){return[this.x,this.y]},clone:function(){return new THREE.Vector2(this.x,this.y)}});THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; +THREE.extend(THREE.Vector3.prototype,{set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ +a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), +this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x* +b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements,e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]); +this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z,a=a.w,h=a*b+f*d-g*c,i=a*c+g*b-e*d,k=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+i*-g-k*-f;this.y=i*a+b*-f+k*-e-h*-g;this.z=k*a+b*-g+h*-f-i*-e;return this},applyEuler:function(){var a=new THREE.Quaternion;return function(b,c){var d=a.setFromEuler(b,c);this.applyQuaternion(d);return this}}(),applyAxisAngle:function(){var a= +new THREE.Quaternion;return function(b,c){var d=a.setFromAxisAngle(b,c);this.applyQuaternion(d);return this}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a,this.z/=a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x= +a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y* +this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."), +this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},projectOnVector:function(){var a=new THREE.Vector3;return function(b){a.copy(b).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(), +reflect:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b).multiplyScalar(2);return this.subVectors(a,this)}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,a=this.z-a.z;return b*b+c*c+a*a},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14]; +return this},setEulerFromRotationMatrix:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.elements,e=d[0],f=d[4],g=d[8],h=d[1],i=d[5],k=d[9],l=d[2],m=d[6],d=d[10];void 0===b||"XYZ"===b?(this.y=Math.asin(c(g)),0.99999>Math.abs(g)?(this.x=Math.atan2(-k,d),this.z=Math.atan2(-f,e)):(this.x=Math.atan2(m,i),this.z=0)):"YXZ"===b?(this.x=Math.asin(-c(k)),0.99999>Math.abs(k)?(this.y=Math.atan2(g,d),this.z=Math.atan2(h,i)):(this.y=Math.atan2(-l,e),this.z=0)):"ZXY"===b?(this.x=Math.asin(c(m)), +0.99999>Math.abs(m)?(this.y=Math.atan2(-l,d),this.z=Math.atan2(-f,i)):(this.y=0,this.z=Math.atan2(h,e))):"ZYX"===b?(this.y=Math.asin(-c(l)),0.99999>Math.abs(l)?(this.x=Math.atan2(m,d),this.z=Math.atan2(h,e)):(this.x=0,this.z=Math.atan2(-f,i))):"YZX"===b?(this.z=Math.asin(c(h)),0.99999>Math.abs(h)?(this.x=Math.atan2(-k,i),this.y=Math.atan2(-l,e)):(this.x=0,this.y=Math.atan2(g,d))):"XZY"===b&&(this.z=Math.asin(-c(f)),0.99999>Math.abs(f)?(this.x=Math.atan2(m,i),this.y=Math.atan2(g,e)):(this.x=Math.atan2(-k, +d),this.y=0));return this},setEulerFromQuaternion:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.x*a.x,e=a.y*a.y,f=a.z*a.z,g=a.w*a.w;void 0===b||"XYZ"===b?(this.x=Math.atan2(2*(a.x*a.w-a.y*a.z),g-d-e+f),this.y=Math.asin(c(2*(a.x*a.z+a.y*a.w))),this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g+d-e-f)):"YXZ"===b?(this.x=Math.asin(c(2*(a.x*a.w-a.y*a.z))),this.y=Math.atan2(2*(a.x*a.z+a.y*a.w),g-d-e+f),this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g-d+e-f)):"ZXY"===b?(this.x=Math.asin(c(2*(a.x*a.w+ +a.y*a.z))),this.y=Math.atan2(2*(a.y*a.w-a.z*a.x),g-d-e+f),this.z=Math.atan2(2*(a.z*a.w-a.x*a.y),g-d+e-f)):"ZYX"===b?(this.x=Math.atan2(2*(a.x*a.w+a.z*a.y),g-d-e+f),this.y=Math.asin(c(2*(a.y*a.w-a.x*a.z))),this.z=Math.atan2(2*(a.x*a.y+a.z*a.w),g+d-e-f)):"YZX"===b?(this.x=Math.atan2(2*(a.x*a.w-a.z*a.y),g-d+e-f),this.y=Math.atan2(2*(a.y*a.w-a.x*a.z),g+d-e-f),this.z=Math.asin(c(2*(a.x*a.y+a.z*a.w)))):"XZY"===b&&(this.x=Math.atan2(2*(a.x*a.w+a.y*a.z),g-d+e-f),this.y=Math.atan2(2*(a.x*a.z+a.y*a.w),g+d- +e-f),this.z=Math.asin(c(2*(a.z*a.w-a.x*a.y))));return this},getScaleFromMatrix:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},toArray:function(){return[this.x,this.y,this.z]},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}});THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; +THREE.extend(THREE.Vector4.prototype,{set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y; +case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a, +b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b= +this.x,c=this.y,d=this.z,e=this.w,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(this.x/=a,this.y/=a,this.z/=a,this.w/=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this}, +setAxisAngleFromRotationMatrix:function(a){var b,c,d,a=a.elements,e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],i=a[9];c=a[2];b=a[6];var k=a[10];if(0.01>Math.abs(d-g)&&0.01>Math.abs(f-c)&&0.01>Math.abs(i-b)){if(0.1>Math.abs(d+g)&&0.1>Math.abs(f+c)&&0.1>Math.abs(i+b)&&0.1>Math.abs(e+h+k-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;k=(k+1)/2;d=(d+g)/4;f=(f+c)/4;i=(i+b)/4;e>h&&e>k?0.01>e?(b=0,d=c=0.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):h>k?0.01>h?(b=0.707106781,c=0,d=0.707106781):(c=Math.sqrt(h), +b=d/c,d=i/c):0.01>k?(c=b=0.707106781,d=0):(d=Math.sqrt(k),b=f/d,c=i/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-i)*(b-i)+(f-c)*(f-c)+(g-d)*(g-d));0.001>Math.abs(a)&&(a=1);this.x=(b-i)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+k-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);this.wb.w&&(this.w=b.w);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+ +this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},toArray:function(){return[this.x, +this.y,this.z,this.w]},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}});THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; +THREE.extend(THREE.Line3.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(0.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, +b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); +this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}});THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; +THREE.extend(THREE.Box2.prototype,{set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0this.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new THREE.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(0.5);this.min.copy(b).sub(d); +this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a){return new THREE.Vector2((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/ +(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max); +return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}});THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; +THREE.extend(THREE.Box3.prototype,{set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0this.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y),b.zthis.max.z&&(this.max.z=b.z)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new THREE.Vector3; +return function(b,c){var d=a.copy(c).multiplyScalar(0.5);this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<= +this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a){return new THREE.Vector3((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min, +this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a=new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=0.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3, +new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x, +this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}});THREE.Matrix3=function(a,b,c,d,e,f,g,h,i){this.elements=new Float32Array(9);this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,g||0,h||0,void 0!==i?i:1)}; +THREE.extend(THREE.Matrix3.prototype,{set:function(a,b,c,d,e,f,g,h,i){var k=this.elements;k[0]=a;k[3]=b;k[6]=c;k[1]=d;k[4]=e;k[7]=f;k[2]=g;k[5]=h;k[8]=i;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)},multiplyVector3Array:function(){var a= +new THREE.Vector3;return function(b){for(var c=0,d=b.length;c=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)- +this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a); +this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}});THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; +THREE.extend(THREE.Frustum.prototype,{set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,a=c[0],d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],i=c[6],k=c[7],l=c[8],m=c[9],n=c[10],s=c[11],r=c[12],p=c[13],q=c[14],c=c[15];b[0].setComponents(f-a,k-g,s-l,c-r).normalize();b[1].setComponents(f+ +a,k+g,s+l,c+r).normalize();b[2].setComponents(f+d,k+h,s+m,c+p).normalize();b[3].setComponents(f-d,k-h,s-m,c-p).normalize();b[4].setComponents(f-e,k-i,s-n,c-q).normalize();b[5].setComponents(f+e,k+i,s+n,c+q).normalize();return this},intersectsObject:function(){var a=new THREE.Vector3;return function(b){var c=b.matrixWorld,d=this.planes,b=-b.geometry.boundingSphere.radius*c.getMaxScaleOnAxis();a.getPositionFromMatrix(c);for(c=0;6>c;c++)if(d[c].distanceToPoint(a)d;d++)if(b[d].distanceToPoint(c)c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}});THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; +THREE.extend(THREE.Plane.prototype,{set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,c);return this}}(), +copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, +b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),a=this.distanceToPoint(a.end);return 0>b&&0a&&0f||1c?c:a},clampBottom:function(a,b){return a=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a, +b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(0.5-Math.random())},sign:function(a){return 0>a?-1:0this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1: +f+2;k=this.points[c[0]];l=this.points[c[1]];m=this.points[c[2]];n=this.points[c[3]];h=g*g;i=g*h;d.x=b(k.x,l.x,m.x,n.x,g,h,i);d.y=b(k.y,l.y,m.y,n.y,g,h,i);d.z=b(k.z,l.z,m.z,n.z,g,h,i);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a=b.x+b.y}}(); +THREE.extend(THREE.Triangle.prototype,{constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return 0.5*a.cross(b).length()}}(), +midpoint:function(a){return(a||new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&& +a.b.equals(this.b)&&a.c.equals(this.c)},clone:function(){return(new THREE.Triangle).copy(this)}});THREE.Vertex=function(a){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.");return a};THREE.UV=function(a,b){console.warn("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.");return new THREE.Vector2(a,b)};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; +THREE.extend(THREE.Clock.prototype,{start:function(){this.oldTime=this.startTime=void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now(), +a=0.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}});THREE.EventDispatcher=function(){var a={};this.addEventListener=function(b,c){void 0===a[b]&&(a[b]=[]);-1===a[b].indexOf(c)&&a[b].push(c)};this.removeEventListener=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)};this.dispatchEvent=function(b){var c=a[b.type];if(void 0!==c){b.target=this;for(var d=0,e=c.length;dh.scale.x)return k;k.push({distance:i,point:h.position,face:null,object:h})}else if(h instanceof +a.Mesh){f.getPositionFromMatrix(h.matrixWorld);b.set(f,h.geometry.boundingSphere.radius*h.matrixWorld.getMaxScaleOnAxis());if(!i.ray.isIntersectionSphere(b))return k;var s=h.geometry,r=s.vertices,p=h.material instanceof a.MeshFaceMaterial,q=!0===p?h.material.materials:null,y=h.material.side,v,z,t,A=i.precision;h.matrixRotationWorld.extractRotation(h.matrixWorld);g.getInverse(h.matrixWorld);c.copy(i.ray).applyMatrix4(g);for(var I=0,C=s.faces.length;IG)){y=y.side;if(y!==a.DoubleSide&&(v=c.direction.dot(d.normal),!(y===a.FrontSide?0>v:0i.far)){e=c.at(G,e);if(x instanceof a.Face3){if(y=r[x.a],v=r[x.b],z=r[x.c],!a.Triangle.containsPoint(e,y,v,z))continue}else if(x instanceof a.Face4){if(y=r[x.a],v=r[x.b],z=r[x.c],t=r[x.d],!a.Triangle.containsPoint(e,y,v,t)&&!a.Triangle.containsPoint(e,v,z,t))continue}else throw Error("face type not supported"); +k.push({distance:G,point:i.ray.at(G),face:x,faceIndex:I,object:h})}}}}}},k=function(a,b,c){for(var a=a.getDescendants(),d=0,e=a.length;de&&0>f||0>g&&0>h)return!1;0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f)));0>g?c=Math.max(c,g/(g-h)):0>h&&(d=Math.min(d,g/(g-h)));if(d< +c)return!1;a.lerp(b,c);b.lerp(a,1-d);return!0}var e,f,g=[],h=0,i,k,l=[],m=0,n,s,r=[],p=0,q,y=[],v=0,z,t,A=[],I=0,C,x,G=[],J=0,E={objects:[],sprites:[],lights:[],elements:[]},H=new THREE.Vector3,B=new THREE.Vector4,W=new THREE.Box3(new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,1,1)),F=new THREE.Box3,K=Array(3),L=Array(4),U=new THREE.Matrix4,fa=new THREE.Matrix4,Ca,$a=new THREE.Matrix4,M=new THREE.Matrix3,ca=new THREE.Matrix3,qa=new THREE.Vector3,ha=new THREE.Frustum,ra=new THREE.Vector4,N=new THREE.Vector4; +this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);fa.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);return a.applyProjection(fa)};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);fa.multiplyMatrices(b.matrixWorld,b.projectionMatrixInverse);return a.applyProjection(fa)};this.pickingRay=function(a,b){a.z=-1;var c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.sub(a).normalize();return new THREE.Raycaster(a, +c)};this.projectScene=function(g,h,m,Pa){var ta=!1,ka,aa,pa,Y,da,la,Z,oa,gb,nb,ia,Wa,ab;x=t=q=s=0;E.elements.length=0;g.updateMatrixWorld();void 0===h.parent&&h.updateMatrixWorld();U.copy(h.matrixWorldInverse.getInverse(h.matrixWorld));fa.multiplyMatrices(h.projectionMatrix,U);ca.getInverse(U);ca.transpose();ha.setFromMatrix(fa);f=0;E.objects.length=0;E.sprites.length=0;E.lights.length=0;var Fa=function(b){for(var c=0,d=b.children.length;ci.positionScreen.x||1i.positionScreen.y||1i.positionScreen.z||1(Z.positionScreen.x-Y.positionScreen.x)*(da.positionScreen.y-Y.positionScreen.y)-(Z.positionScreen.y-Y.positionScreen.y)*(da.positionScreen.x-Y.positionScreen.x),la===THREE.DoubleSide||ta===(la===THREE.FrontSide))s===p?(ia=new THREE.RenderableFace3,r.push(ia),p++,s++,n=ia):n=r[s++],n.v1.copy(Y),n.v2.copy(da),n.v3.copy(Z);else continue; +else continue;else if(aa instanceof THREE.Face4)if(Y=l[aa.a],da=l[aa.b],Z=l[aa.c],ia=l[aa.d],L[0]=Y.positionScreen,L[1]=da.positionScreen,L[2]=Z.positionScreen,L[3]=ia.positionScreen,!0===Y.visible||!0===da.visible||!0===Z.visible||!0===ia.visible||W.isIntersectionBox(F.setFromPoints(L)))if(ta=0>(ia.positionScreen.x-Y.positionScreen.x)*(da.positionScreen.y-Y.positionScreen.y)-(ia.positionScreen.y-Y.positionScreen.y)*(da.positionScreen.x-Y.positionScreen.x)||0>(da.positionScreen.x-Z.positionScreen.x)* +(ia.positionScreen.y-Z.positionScreen.y)-(da.positionScreen.y-Z.positionScreen.y)*(ia.positionScreen.x-Z.positionScreen.x),la===THREE.DoubleSide||ta===(la===THREE.FrontSide)){if(q===v){var ub=new THREE.RenderableFace4;y.push(ub);v++;q++;n=ub}else n=y[q++];n.v1.copy(Y);n.v2.copy(da);n.v3.copy(Z);n.v4.copy(ia)}else continue;else continue;n.normalModel.copy(aa.normal);!1===ta&&(la===THREE.BackSide||la===THREE.DoubleSide)&&n.normalModel.negate();n.normalModel.applyMatrix3(M).normalize();n.normalModelView.copy(n.normalModel).applyMatrix3(ca); +n.centroidModel.copy(aa.centroid).applyMatrix4(Ca);Z=aa.vertexNormals;Y=0;for(da=Z.length;YB.z&&(x===J?(ta=new THREE.RenderableParticle,G.push(ta),J++,x++,C=ta):C=G[x++],C.object=oa,C.x=B.x/B.w,C.y=B.y/B.w,C.z=B.z,C.rotation=oa.rotation.z,C.scale.x=oa.scale.x*Math.abs(C.x-(B.x+h.projectionMatrix.elements[0])/ +(B.w+h.projectionMatrix.elements[12])),C.scale.y=oa.scale.y*Math.abs(C.y-(B.y+h.projectionMatrix.elements[5])/(B.w+h.projectionMatrix.elements[13])),C.material=oa.material,E.elements.push(C)));!0===Pa&&E.elements.sort(c);return E}};THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=void 0!==f?f:0;this.centroid=new THREE.Vector3}; +THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;be?-1:1,f.vertexTangents[d]=new THREE.Vector4(B.x,B.y,B.z,e)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;ci;i++)if(h[i]==h[(i+1)%3]){e.push(f);break}}else if(a instanceof THREE.Face4){a.a=c[a.a];a.b=c[a.b];a.c=c[a.c];a.d=c[a.d];h=[a.a,a.b,a.c,a.d];d=-1;for(i=0;4>i;i++)h[i]==h[(i+1)%4]&&(0<=d&&e.push(f),d=i);if(0<=d){h.splice(d,1);var l=new THREE.Face3(h[0],h[1],h[2],a.normal,a.color,a.materialIndex);h=0;for(i=this.faceVertexUvs.length;hb.max.x&&(b.max.x=c),db.max.y&&(b.max.y=d),eb.max.z&&(b.max.z=e)}if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere= +new THREE.Sphere);var a=this.attributes.position.array;if(a){for(var b,c=0,d,e,f=0,g=a.length;fc&&(c=b);this.boundingSphere.radius=Math.sqrt(c)}},computeVertexNormals:function(){if(this.attributes.position){var a,b,c,d;a=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(a),numItems:a};else{a=0;for(b=this.attributes.normal.array.length;aqa?-1:1;h[4*a]=U.x;h[4*a+1]=U.y;h[4*a+2]=U.z;h[4*a+3]=M}if(void 0===this.attributes.index||void 0===this.attributes.position|| +void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;if(void 0===this.attributes.tangent){var g=4*f;this.attributes.tangent={itemSize:4,array:new Float32Array(g),numItems:g}}for(var h=this.attributes.tangent.array,i=[],k=[],g=0;ga.length?".":a.join("/"))+"/"},initMaterials:function(a,b){for(var c=[],d=0;da.opacity)i.transparent=a.transparent;void 0!==a.depthTest&&(i.depthTest=a.depthTest);void 0!==a.depthWrite&&(i.depthWrite=a.depthWrite);void 0!==a.visible&&(i.visible=a.visible);void 0!==a.flipSided&&(i.side=THREE.BackSide); +void 0!==a.doubleSided&&(i.side=THREE.DoubleSide);void 0!==a.wireframe&&(i.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"===a.vertexColors?i.vertexColors=THREE.FaceColors:a.vertexColors&&(i.vertexColors=THREE.VertexColors));a.colorDiffuse?i.color=f(a.colorDiffuse):a.DbgColor&&(i.color=a.DbgColor);a.colorSpecular&&(i.specular=f(a.colorSpecular));a.colorAmbient&&(i.ambient=f(a.colorAmbient));a.transparency&&(i.opacity=a.transparency);a.specularCoef&&(i.shininess=a.specularCoef);a.mapDiffuse&& +b&&e(i,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&e(i,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&e(i,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&e(i,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&e(i,"specularMap",a.mapSpecular,a.mapSpecularRepeat, +a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapBumpScale&&(i.bumpScale=a.mapBumpScale);a.mapNormal?(h=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(h.uniforms),k.tNormal.value=i.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),i.map&&(k.tDiffuse.value=i.map,k.enableDiffuse.value=!0),i.specularMap&&(k.tSpecular.value=i.specularMap,k.enableSpecular.value=!0),i.lightMap&&(k.tAO.value=i.lightMap,k.enableAO.value=!0),k.uDiffuseColor.value.setHex(i.color), +k.uSpecularColor.value.setHex(i.specular),k.uAmbientColor.value.setHex(i.ambient),k.uShininess.value=i.shininess,void 0!==i.opacity&&(k.uOpacity.value=i.opacity),h=new THREE.ShaderMaterial({fragmentShader:h.fragmentShader,vertexShader:h.vertexShader,uniforms:k,lights:!0,fog:!0}),i.transparent&&(h.transparent=!0)):h=new THREE[h](i);void 0!==a.DbgName&&(h.name=a.DbgName);return h}};THREE.ImageLoader=function(){THREE.EventDispatcher.call(this);this.crossOrigin=null};THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b){var c=this;void 0===b&&(b=new Image);b.addEventListener("load",function(){c.dispatchEvent({type:"load",content:b})},!1);b.addEventListener("error",function(){c.dispatchEvent({type:"error",message:"Couldn't load URL ["+a+"]"})},!1);c.crossOrigin&&(b.crossOrigin=c.crossOrigin);b.src=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)}; +THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var h=JSON.parse(f.responseText);a.createModel(h,c,d)}else console.warn("THREE.JSONLoader: ["+b+"] seems to be unreachable or file there is empty");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load ["+b+"] ["+f.status+"]");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")), +e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)}; +THREE.JSONLoader.prototype.createModel=function(a,b,c){var d=new THREE.Geometry,e=void 0!==a.scale?1/a.scale:1,f,g,h,i,k,l,m,n,s,r,p,q,y,v,z,t=a.faces;r=a.vertices;var A=a.normals,I=a.colors,C=0;for(f=0;fF.parameters.opacity&& +(F.parameters.transparent=!0);F.parameters.normalMap?(E=THREE.ShaderLib.normalmap,B=THREE.UniformsUtils.clone(E.uniforms),q=F.parameters.color,W=F.parameters.specular,p=F.parameters.ambient,H=F.parameters.shininess,B.tNormal.value=x.textures[F.parameters.normalMap],F.parameters.normalScale&&B.uNormalScale.value.set(F.parameters.normalScale[0],F.parameters.normalScale[1]),F.parameters.map&&(B.tDiffuse.value=F.parameters.map,B.enableDiffuse.value=!0),F.parameters.envMap&&(B.tCube.value=F.parameters.envMap, +B.enableReflection.value=!0,B.uReflectivity.value=F.parameters.reflectivity),F.parameters.lightMap&&(B.tAO.value=F.parameters.lightMap,B.enableAO.value=!0),F.parameters.specularMap&&(B.tSpecular.value=x.textures[F.parameters.specularMap],B.enableSpecular.value=!0),F.parameters.displacementMap&&(B.tDisplacement.value=x.textures[F.parameters.displacementMap],B.enableDisplacement.value=!0,B.uDisplacementBias.value=F.parameters.displacementBias,B.uDisplacementScale.value=F.parameters.displacementScale), +B.uDiffuseColor.value.setHex(q),B.uSpecularColor.value.setHex(W),B.uAmbientColor.value.setHex(p),B.uShininess.value=H,F.parameters.opacity&&(B.uOpacity.value=F.parameters.opacity),s=new THREE.ShaderMaterial({fragmentShader:E.fragmentShader,vertexShader:E.vertexShader,uniforms:B,lights:!0,fog:!0})):s=new THREE[F.type](F.parameters);x.materials[K]=s}for(K in J.materials)if(F=J.materials[K],F.parameters.materials){L=[];for(q=0;qh.end&&(h.end=e);b||(b=g)}}a.firstAnimation=b}; +THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1E3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")}; +THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& +(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; +THREE.MorphAnimMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.MorphAnimMesh(this.geometry,this.material));a.duration=this.duration;a.mirroredLoop=this.mirroredLoop;a.time=this.time;a.lastKeyframe=this.lastKeyframe;a.currentKeyframe=this.currentKeyframe;a.direction=this.direction;a.directionBackwards=this.directionBackwards;THREE.Mesh.prototype.clone.call(this,a);return a};THREE.Ribbon=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=b};THREE.Ribbon.prototype=Object.create(THREE.Object3D.prototype);THREE.Ribbon.prototype.clone=function(a){void 0===a&&(a=new THREE.Ribbon(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.LOD=function(){THREE.Object3D.call(this);this.LODs=[]};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype);THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);for(var b=Math.abs(b),c=0;c=this.LODs[b].visibleAtDistance)this.LODs[b-1].object3D.visible=!1,this.LODs[b].object3D.visible=!0;else break;for(;bI&&t.clearRect(Ka.min.x|0,Ka.min.y|0,Ka.max.x-Ka.min.x|0,Ka.max.y-Ka.min.y|0),0=j||(j*=f.intensity,c.add(gb.multiplyScalar(j)))}else f instanceof THREE.PointLight&&(g=bb.getPositionFromMatrix(f.matrixWorld),j=b.dot(bb.subVectors(g,a).normalize()),0>=j||(j*=0==f.distance?1:1-Math.min(a.distanceTo(g)/f.distance,1),0!=j&&(j*=f.intensity,c.add(gb.multiplyScalar(j)))))}}function x(a,d,e,f,g,j,h,i){l.info.render.vertices+= +3;l.info.render.faces++;b(i.opacity);c(i.blending);M=a.positionScreen.x;ca=a.positionScreen.y;qa=d.positionScreen.x;ha=d.positionScreen.y;ra=e.positionScreen.x;N=e.positionScreen.y;y(M,ca,qa,ha,ra,N);(i instanceof THREE.MeshLambertMaterial||i instanceof THREE.MeshPhongMaterial)&&null===i.map?(Z.copy(i.color),oa.copy(i.emissive),i.vertexColors===THREE.FaceColors&&Z.multiply(h.color),!0===gc?!1===i.wireframe&&i.shading==THREE.SmoothShading&&3==h.vertexNormalsLength?(pa.copy(vb),Y.copy(vb),da.copy(vb), +q(h.v1.positionWorld,h.vertexNormalsModel[0],pa),q(h.v2.positionWorld,h.vertexNormalsModel[1],Y),q(h.v3.positionWorld,h.vertexNormalsModel[2],da),pa.multiply(Z).add(oa),Y.multiply(Z).add(oa),da.multiply(Z).add(oa),la.addColors(Y,da).multiplyScalar(0.5),Fa=E(pa,Y,da,la),G(M,ca,qa,ha,ra,N,0,0,1,0,0,1,Fa)):(aa.copy(vb),q(h.centroidModel,h.normalModel,aa),aa.multiply(Z).add(oa),!0===i.wireframe?C(aa,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):A(aa)):!0===i.wireframe?C(i.color,i.wireframeLinewidth, +i.wireframeLinecap,i.wireframeLinejoin):A(i.color)):i instanceof THREE.MeshBasicMaterial||i instanceof THREE.MeshLambertMaterial||i instanceof THREE.MeshPhongMaterial?null!==i.map?i.map.mapping instanceof THREE.UVMapping&&(Xa=h.uvs[0],F(M,ca,qa,ha,ra,N,Xa[f].x,Xa[f].y,Xa[g].x,Xa[g].y,Xa[j].x,Xa[j].y,i.map)):null!==i.envMap?i.envMap.mapping instanceof THREE.SphericalReflectionMapping&&(bb.copy(h.vertexNormalsModelView[f]),ub=0.5*bb.x+0.5,Ib=0.5*bb.y+0.5,bb.copy(h.vertexNormalsModelView[g]),Jb=0.5* +bb.x+0.5,fc=0.5*bb.y+0.5,bb.copy(h.vertexNormalsModelView[j]),Ab=0.5*bb.x+0.5,mc=0.5*bb.y+0.5,F(M,ca,qa,ha,ra,N,ub,Ib,Jb,fc,Ab,mc,i.envMap)):(aa.copy(i.color),i.vertexColors===THREE.FaceColors&&aa.multiply(h.color),!0===i.wireframe?C(aa,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):A(aa)):i instanceof THREE.MeshDepthMaterial?(Wa=p.near,ab=p.far,pa.r=pa.g=pa.b=1-k(a.positionScreen.z*a.positionScreen.w,Wa,ab),Y.r=Y.g=Y.b=1-k(d.positionScreen.z*d.positionScreen.w,Wa,ab),da.r=da.g=da.b= +1-k(e.positionScreen.z*e.positionScreen.w,Wa,ab),la.addColors(Y,da).multiplyScalar(0.5),Fa=E(pa,Y,da,la),G(M,ca,qa,ha,ra,N,0,0,1,0,0,1,Fa)):i instanceof THREE.MeshNormalMaterial&&(i.shading==THREE.FlatShading?(a=h.normalModelView,aa.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),!0===i.wireframe?C(aa,i.wireframeLinewidth,i.wireframeLinecap,i.wireframeLinejoin):A(aa)):i.shading==THREE.SmoothShading&&(a=h.vertexNormalsModelView[f],pa.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),a= +h.vertexNormalsModelView[g],Y.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),a=h.vertexNormalsModelView[j],da.setRGB(a.x,a.y,a.z).multiplyScalar(0.5).addScalar(0.5),la.addColors(Y,da).multiplyScalar(0.5),Fa=E(pa,Y,da,la),G(M,ca,qa,ha,ra,N,0,0,1,0,0,1,Fa)))}function y(a,b,c,d,e,f){t.beginPath();t.moveTo(a,b);t.lineTo(c,d);t.lineTo(e,f);t.closePath()}function B(a,b,c,d,e,f,g,j){t.beginPath();t.moveTo(a,b);t.lineTo(c,d);t.lineTo(e,f);t.lineTo(g,j);t.closePath()}function C(a,b,c,j){d(b);e(c); +f(j);g(a.getStyle());t.stroke();Va.expandByScalar(2*b)}function A(a){h(a.getStyle());t.fill()}function F(a,b,c,d,e,f,g,j,i,wa,k,l,n){if(!(n instanceof THREE.DataTexture||void 0===n.image||0==n.image.width)){if(!0===n.needsUpdate){var m=n.wrapS==THREE.RepeatWrapping,hb=n.wrapT==THREE.RepeatWrapping;nb[n.id]=t.createPattern(n.image,!0===m&&!0===hb?"repeat":!0===m&&!1===hb?"repeat-x":!1===m&&!0===hb?"repeat-y":"no-repeat");n.needsUpdate=!1}void 0===nb[n.id]?h("rgba(0,0,0,1)"):h(nb[n.id]);var m=n.offset.x/ +n.repeat.x,hb=n.offset.y/n.repeat.y,p=n.image.width*n.repeat.x,q=n.image.height*n.repeat.y,g=(g+m)*p,j=(1-j+hb)*q,c=c-a,d=d-b,e=e-a,f=f-b,i=(i+m)*p-g,wa=(1-wa+hb)*q-j,k=(k+m)*p-g,l=(1-l+hb)*q-j,m=i*l-k*wa;0===m?(void 0===ia[n.id]&&(b=document.createElement("canvas"),b.width=n.image.width,b.height=n.image.height,b=b.getContext("2d"),b.drawImage(n.image,0,0),ia[n.id]=b.getImageData(0,0,n.image.width,n.image.height).data),b=ia[n.id],g=4*(Math.floor(g)+Math.floor(j)*n.image.width),aa.setRGB(b[g]/255, +b[g+1]/255,b[g+2]/255),A(aa)):(m=1/m,n=(l*c-wa*e)*m,wa=(l*d-wa*f)*m,c=(i*e-k*c)*m,d=(i*f-k*d)*m,a=a-n*g-c*j,g=b-wa*g-d*j,t.save(),t.transform(n,wa,c,d,a,g),t.fill(),t.restore())}}function G(a,b,c,d,e,f,g,j,i,h,wa,k,n){var l,m;l=n.width-1;m=n.height-1;g*=l;j*=m;c-=a;d-=b;e-=a;f-=b;i=i*l-g;h=h*m-j;wa=wa*l-g;k=k*m-j;m=1/(i*k-wa*h);l=(k*c-h*e)*m;h=(k*d-h*f)*m;c=(i*e-wa*c)*m;d=(i*f-wa*d)*m;a=a-l*g-c*j;b=b-h*g-d*j;t.save();t.transform(l,h,c,d,a,b);t.clip();t.drawImage(n,0,0);t.restore()}function E(a,b, +c,d){Ra[0]=255*a.r|0;Ra[1]=255*a.g|0;Ra[2]=255*a.b|0;Ra[4]=255*b.r|0;Ra[5]=255*b.g|0;Ra[6]=255*b.b|0;Ra[8]=255*c.r|0;Ra[9]=255*c.g|0;Ra[10]=255*c.b|0;Ra[12]=255*d.r|0;Ra[13]=255*d.g|0;Ra[14]=255*d.b|0;j.putImageData(yb,0,0);Sa.drawImage(xb,0,0);return cb}function I(a,b){var c=b.x-a.x,d=b.y-a.y,e=c*c+d*d;0!==e&&(e=1/Math.sqrt(e),c*=e,d*=e,b.x+=c,b.y+=d,a.x-=c,a.y-=d)}if(!1===p instanceof THREE.Camera)console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");else{!0=== +this.autoClear&&this.clear();t.setTransform(1,0,0,-1,v,z);l.info.render.vertices=0;l.info.render.faces=0;m=r.projectScene(a,p,this.sortObjects,this.sortElements);n=m.elements;s=m.lights;gc=0>1,nd=H.height>>1,Cb=wa.scale.x*v,Db=wa.scale.y*z,Bb=Cb*md,hb=Db*nd,Va.min.set(X.x-Bb,X.y-hb),Va.max.set(X.x+Bb,X.y+hb),!1!==pb.isIntersectionBox(Va)&&(t.save(),t.translate(X.x,X.y),t.rotate(-wa.rotation),t.scale(Cb,-Db),t.translate(-md,-nd),t.drawImage(H,0,0),t.restore())):P instanceof THREE.ParticleCanvasMaterial&&(Bb=wa.scale.x*v,hb=wa.scale.y*z,Va.min.set(X.x-Bb,X.y-hb),Va.max.set(X.x+Bb,X.y+hb),!1!==pb.isIntersectionBox(Va)&&(g(P.color.getStyle()), +h(P.color.getStyle()),t.save(),t.translate(X.x,X.y),t.rotate(-wa.rotation),t.scale(Bb,hb),P.program(t),t.restore()))}else if(H instanceof THREE.RenderableLine)K=H.v1,L=H.v2,K.positionScreen.x*=v,K.positionScreen.y*=z,L.positionScreen.x*=v,L.positionScreen.y*=z,Va.setFromPoints([K.positionScreen,L.positionScreen]),!0===pb.isIntersectionBox(Va)&&(X=K,wa=L,b(P.opacity),c(P.blending),t.beginPath(),t.moveTo(X.positionScreen.x,X.positionScreen.y),t.lineTo(wa.positionScreen.x,wa.positionScreen.y),P instanceof +THREE.LineBasicMaterial?(d(P.linewidth),e(P.linecap),f(P.linejoin),g(P.color.getStyle()),i(null,null),t.stroke(),Va.expandByScalar(2*P.linewidth)):P instanceof THREE.LineDashedMaterial&&(d(P.linewidth),e(P.linecap),f(P.linejoin),g(P.color.getStyle()),i(P.dashSize,P.gapSize),t.stroke(),Va.expandByScalar(2*P.linewidth)));else if(H instanceof THREE.RenderableFace3){K=H.v1;L=H.v2;U=H.v3;if(-1>K.positionScreen.z||1L.positionScreen.z||1 +U.positionScreen.z||1K.positionScreen.z|| +1L.positionScreen.z||1U.positionScreen.z||1fa.positionScreen.z||1 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif", +lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\nvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n#ifdef DOUBLE_SIDED\nvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n#endif\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif", +lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif", +lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvWorldPosition = worldPosition.xyz;\n#endif", +lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;", +lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#ifdef USE_NORMALMAP\nnormal = perturbNormal2Arb( -viewPosition, normal );\n#elif defined( USE_BUMPMAP )\nnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += diffuse * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif", +color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n#ifdef BONE_TEXTURE\nuniform sampler2D boneTexture;\nmat4 getBoneMatrix( const in float i ) {\nfloat j = i * 4.0;\nfloat x = mod( j, N_BONE_PIXEL_X );\nfloat y = floor( j / N_BONE_PIXEL_X );\nconst float dx = 1.0 / N_BONE_PIXEL_X;\nconst float dy = 1.0 / N_BONE_PIXEL_Y;\ny = dy * ( y + 0.5 );\nvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\nvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\nvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\nvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\nmat4 bone = mat4( v1, v2, v3, v4 );\nreturn bone;\n}\n#else\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\nmat4 getBoneMatrix( const in float i ) {\nmat4 bone = boneGlobalMatrices[ int(i) ];\nreturn bone;\n}\n#endif\n#endif", +skinbase_vertex:"#ifdef USE_SKINNING\nmat4 boneMatX = getBoneMatrix( skinIndex.x );\nmat4 boneMatY = getBoneMatrix( skinIndex.y );\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n#ifdef USE_MORPHTARGETS\nvec4 skinVertex = vec4( morphed, 1.0 );\n#else\nvec4 skinVertex = vec4( position, 1.0 );\n#endif\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif", +morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\n#endif", +default_vertex:"vec4 mvPosition;\n#ifdef USE_SKINNING\nmvPosition = modelViewMatrix * skinned;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( position, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\n#endif", +skinnormal_vertex:"#ifdef USE_SKINNING\nmat4 skinMatrix = skinWeight.x * boneMatX;\nskinMatrix \t+= skinWeight.y * boneMatY;\n#ifdef USE_MORPHNORMALS\nvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n#else\nvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n#endif\n#endif",defaultnormal_vertex:"vec3 objectNormal;\n#ifdef USE_SKINNING\nobjectNormal = skinnedNormal.xyz;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )\nobjectNormal = morphedNormal;\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )\nobjectNormal = normal;\n#endif\n#ifdef FLIP_SIDED\nobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;", +shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#if defined( SHADOWMAP_TYPE_PCF )\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\nfloat shadow = 0.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.0 * xPixelOffset;\nfloat dy0 = -1.0 * yPixelOffset;\nfloat dx1 = 1.0 * xPixelOffset;\nfloat dy1 = 1.0 * yPixelOffset;\nmat3 shadowKernel;\nmat3 depthKernel;\ndepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( depthKernel[0][0] < shadowCoord.z ) shadowKernel[0][0] = 0.25;\nelse shadowKernel[0][0] = 0.0;\ndepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( depthKernel[0][1] < shadowCoord.z ) shadowKernel[0][1] = 0.25;\nelse shadowKernel[0][1] = 0.0;\ndepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( depthKernel[0][2] < shadowCoord.z ) shadowKernel[0][2] = 0.25;\nelse shadowKernel[0][2] = 0.0;\ndepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( depthKernel[1][0] < shadowCoord.z ) shadowKernel[1][0] = 0.25;\nelse shadowKernel[1][0] = 0.0;\ndepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( depthKernel[1][1] < shadowCoord.z ) shadowKernel[1][1] = 0.25;\nelse shadowKernel[1][1] = 0.0;\ndepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( depthKernel[1][2] < shadowCoord.z ) shadowKernel[1][2] = 0.25;\nelse shadowKernel[1][2] = 0.0;\ndepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( depthKernel[2][0] < shadowCoord.z ) shadowKernel[2][0] = 0.25;\nelse shadowKernel[2][0] = 0.0;\ndepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( depthKernel[2][1] < shadowCoord.z ) shadowKernel[2][1] = 0.25;\nelse shadowKernel[2][1] = 0.0;\ndepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( depthKernel[2][2] < shadowCoord.z ) shadowKernel[2][2] = 0.25;\nelse shadowKernel[2][2] = 0.0;\nvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\nshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\nshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\nvec4 shadowValues;\nshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\nshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\nshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\nshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\nshadow = dot( shadowValues, vec4( 1.0 ) );\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif", +shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"}; +THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b dashSize ) {\ndiscard;\n}\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f", +value:1}},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float mNear;\nuniform float mFar;\nuniform float opacity;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), opacity );\n}"},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:"varying vec3 vNormal;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\ngl_Position = projectionMatrix * mvPosition;\n}", +fragmentShader:"uniform float opacity;\nvarying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\n}"},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null}, +tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f",value:30},uOpacity:{type:"f",value:1},useRefract:{type:"i",value:0}, +uRefractionRatio:{type:"f",value:0.98},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float uRefractionRatio;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\n#ifdef FLIP_SIDED\nfinalNormal = -finalNormal;\n#endif\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\nfloat pointDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\npointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\npointVector = normalize( pointVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\nfloat spotDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\nspotVector = normalize( spotVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n#endif\nspotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;\nvec3 spotHalfVector = normalize( spotVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += uDiffuseColor * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;\n#endif\nif ( enableReflection ) {\nvec3 vReflect;\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, normal, uRefractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, normal );\n}\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}", +THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", +THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING\nvNormal = normalize( normalMatrix * skinnedNormal.xyz );\nvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\nvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n#else\nvNormal = normalize( normalMatrix * normal );\nvTangent = normalize( normalMatrix * tangent.xyz );\n#endif\nvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\nvUv = uv * uRepeat + uOffset;\nvec3 displacedPosition;\n#ifdef VERTEX_TEXTURES\nif ( enableDisplacement ) {\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\ndisplacedPosition = position + normalize( normal ) * df;\n} else {\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n}\n#else\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n#endif\nvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\nvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\nvWorldPosition = worldPosition.xyz;\nvViewPosition = -mvPosition.xyz;\n#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif\n}"].join("\n")}, +cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vWorldPosition;\nvoid main() {\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\nvWorldPosition = worldPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\nvoid main() {\ngl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n}"}, +depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"vec4 pack_depth( const in float depth ) {\nconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\nconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\nvec4 res = fract( depth * bit_shift );\nres -= res.xxyz * bit_mask;\nreturn res;\n}\nvoid main() {\ngl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n}"}};THREE.WebGLRenderer=function(a){function b(a){if(a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)j.deleteBuffer(a.__webglCustomAttributesList[b].buffer)}function c(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var g=1;"v2"===f.type?g=2:"v3"===f.type?g=3:"v4"===f.type? +g=4:"c"===f.type&&(g=3);f.size=g;f.array=new Float32Array(c*g);f.buffer=j.createBuffer();f.buffer.belongsToAttribute=e;f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}}function d(a,b){var c=b.geometry,d=a.faces3,h=a.faces4,i=3*d.length+4*h.length,k=1*d.length+2*h.length,h=3*d.length+4*h.length,d=e(b,a),n=g(d),l=f(d),m=d.vertexColors?d.vertexColors:!1;a.__vertexArray=new Float32Array(3*i);l&&(a.__normalArray=new Float32Array(3*i));c.hasTangents&&(a.__tangentArray=new Float32Array(4*i));m&& +(a.__colorArray=new Float32Array(3*i));if(n){if(0l;l++)N.autoScaleCubemaps&&!f?(m=k,r=l,t=c.image[l],y=gd,t.width<=y&&t.height<=y||(z=Math.max(t.width,t.height),v=Math.floor(t.width*y/z),y=Math.floor(t.height*y/z),z=document.createElement("canvas"),z.width=v,z.height=y,z.getContext("2d").drawImage(t,0,0,t.width,t.height,0,0,v,y),t=z),m[r]=t):k[l]=c.image[l];l=k[0];m=0===(l.width&l.width-1)&&0===(l.height&l.height-1);r=L(c.format); +t=L(c.type);W(j.TEXTURE_CUBE_MAP,c,m);for(l=0;6>l;l++)if(f){y=k[l].mipmaps;z=0;for(B=y.length;z=Mc&&console.warn("WebGLRenderer: trying to use "+ +a+" texture units while this GPU supports only "+Mc);Y+=1;return a}function C(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getInverse(a._modelViewMatrix);a._normalMatrix.transpose()}function x(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function G(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function J(a){a!==ub&&(j.lineWidth(a),ub=a)}function E(a,b,c){ab!==a&&(a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL),ab=a);if(a&& +(Fa!==b||Xa!==c))j.polygonOffset(b,c),Fa=b,Xa=c}function H(a){for(var a=a.split("\n"),b=0,c=a.length;bb;b++)j.deleteFramebuffer(a.__webglFramebuffer[b]),j.deleteRenderbuffer(a.__webglRenderbuffer[b]); +else j.deleteFramebuffer(a.__webglFramebuffer),j.deleteRenderbuffer(a.__webglRenderbuffer);N.info.memory.textures--},X=function(a){a=a.target;a.removeEventListener("dispose",X);Pc(a)},Pc=function(a){var b=a.program;if(void 0!==b){a.program=void 0;var c,d,e=!1,a=0;for(c=Ma.length;ad.numSupportedMorphTargets?(i.sort(n),i.length=d.numSupportedMorphTargets):i.length>d.numSupportedMorphNormals?i.sort(n):0===i.length&&i.push([0,0]);for(h=0;hxa;xa++)nc=ab[xa],Fb[kb]=nc.x,Fb[kb+1]=nc.y,Fb[kb+2]=nc.z,kb+=3;else for(xa=0;3>xa;xa++)Fb[kb]=Xa.x,Fb[kb+1]=Xa.y,Fb[kb+2]=Xa.z,kb+=3;D=0;for(V=va.length;Dxa;xa++)nc= +ab[xa],Fb[kb]=nc.x,Fb[kb+1]=nc.y,Fb[kb+2]=nc.z,kb+=3;else for(xa=0;4>xa;xa++)Fb[kb]=Xa.x,Fb[kb+1]=Xa.y,Fb[kb+2]=Xa.z,kb+=3;j.bindBuffer(j.ARRAY_BUFFER,sa.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,Fb,Pa)}if(Cc&&pd&&bb){D=0;for(V=ua.length;Dxa;xa++)Ab=pb[xa],Dc[ic]=Ab.x,Dc[ic+1]=Ab.y,ic+=2;D=0;for(V=va.length;Dxa;xa++)Ab=pb[xa],Dc[ic]=Ab.x,Dc[ic+1]=Ab.y,ic+=2;0xa;xa++)yc=ub[xa],Ec[jc]=yc.x,Ec[jc+1]=yc.y,jc+=2;D=0;for(V=va.length;Dxa;xa++)yc=ub[xa],Ec[jc]=yc.x,Ec[jc+1]=yc.y,jc+=2;0f;f++){a.__webglFramebuffer[f]=j.createFramebuffer();a.__webglRenderbuffer[f]=j.createRenderbuffer();j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,i=j.TEXTURE_CUBE_MAP_POSITIVE_X+f;j.bindFramebuffer(j.FRAMEBUFFER, +a.__webglFramebuffer[f]);j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,i,g.__webglTexture,0);F(a.__webglRenderbuffer[f],a)}c&&j.generateMipmap(j.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=j.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:j.createRenderbuffer(),j.bindTexture(j.TEXTURE_2D,a.__webglTexture),W(j.TEXTURE_2D,a,c),j.texImage2D(j.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=j.TEXTURE_2D,j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer), +j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):F(a.__webglRenderbuffer,a),c&&j.generateMipmap(j.TEXTURE_2D);b?j.bindTexture(j.TEXTURE_CUBE_MAP,null):j.bindTexture(j.TEXTURE_2D,null);j.bindRenderbuffer(j.RENDERBUFFER, +null);j.bindFramebuffer(j.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=fc,a=Ab,d=Ib,e=Jb);b!==Pa&&(j.bindFramebuffer(j.FRAMEBUFFER,b),j.viewport(d,e,c,a),Pa=b);mc=c;pb=a};this.shadowMapPlugin=new THREE.ShadowMapPlugin;this.addPrePlugin(this.shadowMapPlugin);this.addPostPlugin(new THREE.SpritePlugin);this.addPostPlugin(new THREE.LensFlarePlugin)};THREE.WebGLRenderTarget=function(a,b,c){THREE.EventDispatcher.call(this);this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1); +this.format=void 0!==c.format?c.format:THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; +THREE.WebGLRenderTarget.prototype.clone=function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;a.generateMipmaps=this.generateMipmaps;a.shareDepthFrom=this.shareDepthFrom;return a}; +THREE.WebGLRenderTarget.prototype.dispose=function(){this.dispatchEvent({type:"dispose"})};THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=!0};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};THREE.RenderableFace3=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.material=this.color=null;this.uvs=[[]];this.z=null};THREE.RenderableFace4=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.v4=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]; +this.material=this.color=null;this.uvs=[[]];this.z=null};THREE.RenderableObject=function(){this.z=this.object=null};THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=this.object=null;this.scale=new THREE.Vector2;this.material=null};THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.material=null};THREE.GeometryUtils={merge:function(a,b){var c,d,e=a.vertices.length,f=b instanceof THREE.Mesh?b.geometry:b,g=a.vertices,h=f.vertices,i=a.faces,k=f.faces,l=a.faceVertexUvs[0],f=f.faceVertexUvs[0];b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),c=b.matrix,d=new THREE.Matrix3,d.getInverse(c),d.transpose());for(var m=0,n=h.length;ma?b(c,e-1):k[e]>8&255,i>>16&255,i>>24&255)),d}d.mipmapCount=1;h[2]&131072&&!1!==b&&(d.mipmapCount=Math.max(1,h[7]));d.isCubemap=h[28]&512?!0:!1;d.width=h[4];d.height=h[3];for(var h=h[1]+4,f=d.width,g=d.height,i=d.isCubemap? +6:1,k=0;km-1?0:m-1,s=m+1>e-1?e-1:m+1,r=0>l-1?0:l-1,p=l+1>d-1?d-1:l+1,q=[],y=[0,0,h[4*(m*d+l)]/255*b];q.push([-1,0,h[4*(m*d+r)]/255*b]);q.push([-1,-1,h[4*(n*d+r)]/255*b]);q.push([0,-1,h[4*(n*d+l)]/255*b]);q.push([1,-1,h[4*(n*d+p)]/255*b]);q.push([1,0,h[4*(m*d+p)]/255*b]);q.push([1,1,h[4*(s*d+p)]/255*b]);q.push([0,1,h[4*(s*d+l)]/255*b]);q.push([-1,1,h[4*(s*d+r)]/255*b]);n=[];r=q.length;for(s=0;se)return null;var f=[],g=[],h=[],i,k,l;if(0=m--){console.log("Warning, unable to triangulate polygon!");break}i=k;e<=i&&(i=0);k=i+1;e<=k&&(k=0);l=k+1;e<=l&&(l=0);var n;a:{var s=n=void 0,r=void 0,p=void 0,q=void 0,y=void 0,v=void 0,z=void 0,t= +void 0,s=a[g[i]].x,r=a[g[i]].y,p=a[g[k]].x,q=a[g[k]].y,y=a[g[l]].x,v=a[g[l]].y;if(1E-10>(p-s)*(v-r)-(q-r)*(y-s))n=!1;else{var A=void 0,I=void 0,C=void 0,x=void 0,G=void 0,J=void 0,E=void 0,H=void 0,B=void 0,W=void 0,B=H=E=t=z=void 0,A=y-p,I=v-q,C=s-y,x=r-v,G=p-s,J=q-r;for(n=0;ni)g=d+1;else if(0b&&(b=0);1d.length-2?d.length-1:a+1;c[3]=a>d.length-3?d.length-1:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);return b}; +THREE.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=g};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype);THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;this.aClockwise||(a=1-a);b=this.aStartAngle+a*b;a=this.aX+this.xRadius*Math.cos(b);b=this.aY+this.yRadius*Math.sin(b);return new THREE.Vector2(a,b)}; +THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype); +THREE.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,e){var a=0.5*(c-a),d=0.5*(d-b),f=e*e;return(2*b-2*c+a+d)*e*f+(-3*b+3*c-2*a-d)*f+a*e+b}}; +THREE.Curve.create=function(a,b){a.prototype=Object.create(THREE.Curve.prototype);a.prototype.getPoint=b;return a};THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b}); +THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b,c;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);a=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(b,c,a)}); +THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b,c;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);c=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return new THREE.Vector3(b,c,a)}); +THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e,a=(d.length-1)*a;e=Math.floor(a);a-=e;c[0]=0==e?e:e-1;c[1]=e;c[2]=e>d.length-2?d.length-1:e+1;c[3]=e>d.length-3?d.length-1:e+2;e=d[c[0]];var f=d[c[1]],g=d[c[2]],c=d[c[3]];b.x=THREE.Curve.Utils.interpolate(e.x,f.x,g.x,c.x,a);b.y=THREE.Curve.Utils.interpolate(e.y,f.y,g.y,c.y,a);b.z=THREE.Curve.Utils.interpolate(e.z,f.z,g.z,c.z,a);return b}); +THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e;e=(d.length-0)*a;a=Math.floor(e);e-=a;a+=0=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; +THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;cb?b=h.x:h.xc?c=h.y:h.yd?d=h.z:h.zMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; +THREE.Path.prototype.toShapes=function(){var a,b,c,d,e=[],f=new THREE.Path;a=0;for(b=this.actions.length;a +h&&(h+=c.length);h%=c.length;0>g&&(g+=k.length);g%=k.length;e=0<=h-1?h-1:c.length-1;f=0<=g-1?g-1:k.length-1;p=[k[g],c[h],c[e]];p=THREE.FontUtils.Triangulate.area(p);q=[k[g],k[f],c[h]];q=THREE.FontUtils.Triangulate.area(q);m+n>p+q&&(h=s,g=l,0>h&&(h+=c.length),h%=c.length,0>g&&(g+=k.length),g%=k.length,e=0<=h-1?h-1:c.length-1,f=0<=g-1?g-1:k.length-1);m=c.slice(0,h);n=c.slice(h);s=k.slice(g);l=k.slice(0,g);f=[k[g],k[f],c[h]];r.push([k[g],c[h],c[e]]);r.push(f);c=m.concat(s).concat(l).concat(n)}return{shape:c, +isolatedPts:r,allpoints:d}},triangulateShape:function(a,b){var c=THREE.Shape.Utils.removeHoles(a,b),d=c.allpoints,e=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,!1),f,g,h,i,k={};f=0;for(g=d.length;fd;d++)i=h[d].x+":"+h[d].y,i=k[i],void 0!==i&&(h[d]=i)}f=0;for(g=e.length;fd;d++)i=h[d].x+":"+h[d].y,i=k[i],void 0!==i&&(h[d]=i)}return c.concat(e)}, +isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+ +this.b3p3(a,e)}};THREE.AnimationHandler=function(){var a=[],b={},c={update:function(b){for(var c=0;ca.hierarchy[c].keys[d].time&& +(a.hierarchy[c].keys[d].time=0),void 0!==a.hierarchy[c].keys[d].rot&&!(a.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var h=a.hierarchy[c].keys[d].rot;a.hierarchy[c].keys[d].rot=new THREE.Quaternion(h[0],h[1],h[2],h[3])}if(a.hierarchy[c].keys.length&&void 0!==a.hierarchy[c].keys[0].morphTargets){h={};for(d=0;ds;s++){c=b[s];g=i.prevKey[c];h=i.nextKey[c];if(h.time<=l){if(kd||1d?0:1;if("pos"===c)if(c=a.position,this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+ +(f[2]-e[2])*d;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)this.points[0]=this.getPrevKeyWith("pos",m,g.index-1).pos,this.points[1]=e,this.points[2]=f,this.points[3]=this.getNextKeyWith("pos",m,h.index+1).pos,d=0.33*d+0.33,e=this.interpolateCatmullRom(this.points,d),c.x=e[0],c.y=e[1],c.z=e[2],this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(d=this.interpolateCatmullRom(this.points,1.01*d), +this.target.set(d[0],d[1],d[2]),this.target.sub(c),this.target.y=0,this.target.normalize(),d=Math.atan2(this.target.x,this.target.z),a.rotation.set(0,d,0))}else"rot"===c?THREE.Quaternion.slerp(e,f,a.quaternion,d):"scl"===c&&(c=a.scale,c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+(f[2]-e[2])*d)}}}}; +THREE.Animation.prototype.interpolateCatmullRom=function(a,b){var c=[],d=[],e,f,g,h,i,k;e=(a.length-1)*b;f=Math.floor(e);e-=f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>a.length-2?f:f+1;c[3]=f>a.length-3?f:f+2;f=a[c[0]];h=a[c[1]];i=a[c[2]];k=a[c[3]];c=e*e;g=e*c;d[0]=this.interpolate(f[0],h[0],i[0],k[0],e,c,g);d[1]=this.interpolate(f[1],h[1],i[1],k[1],e,c,g);d[2]=this.interpolate(f[2],h[2],i[2],k[2],e,c,g);return d}; +THREE.Animation.prototype.interpolate=function(a,b,c,d,e,f,g){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b};THREE.Animation.prototype.getNextKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c=g?b.interpolate(c,g):b.interpolate(c,c.time)}this.data.hierarchy[a].node.updateMatrix();d.matrixWorldNeedsUpdate=!0}}if(this.JITCompile&&void 0===f[0][e]){this.hierarchy[0].updateMatrixWorld(!0);for(a=0;ag?(b=Math.atan2(b.y-a.y,b.x-a.x),a=Math.atan2(c.y-a.y,c.x-a.x),b>a&&(a+=2*Math.PI),c=(b+a)/2,a=-Math.cos(c),c=-Math.sin(c),new THREE.Vector2(a,c)):d.multiplyScalar(g).add(i).sub(a).clone()}function e(c,d){var e,f;for(M=c.length;0<=--M;){e=M;f=M-1;0>f&&(f=c.length-1);for(var g=0,i=s+2*l, +g=0;gMath.abs(c-i)?[new THREE.Vector2(b,1-e),new THREE.Vector2(d,1-f),new THREE.Vector2(k,1-g),new THREE.Vector2(m,1-a)]:[new THREE.Vector2(c,1-e),new THREE.Vector2(i,1-f),new THREE.Vector2(l,1-g),new THREE.Vector2(n,1-a)]}};THREE.ExtrudeGeometry.__v1=new THREE.Vector2;THREE.ExtrudeGeometry.__v2=new THREE.Vector2;THREE.ExtrudeGeometry.__v3=new THREE.Vector2;THREE.ExtrudeGeometry.__v4=new THREE.Vector2; +THREE.ExtrudeGeometry.__v5=new THREE.Vector2;THREE.ExtrudeGeometry.__v6=new THREE.Vector2;THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);!1===a instanceof Array&&(a=[a]);this.shapebb=a[a.length-1].getBoundingBox();this.addShapeList(a,b);this.computeCentroids();this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;cd?(d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]),d.centroid.add(a).add(b).add(c).divideScalar(3),d.normal=d.centroid.clone().normalize(),i.faces.push(d),d=Math.atan2(d.centroid.z,-d.centroid.x),i.faceVertexUvs[0].push([h(a.uv, +a,d),h(b.uv,b,d),h(c.uv,c,d)])):(d-=1,f(a,g(a,b),g(a,c),d),f(g(a,b),b,g(b,c),d),f(g(a,c),g(b,c),c,d),f(g(a,b),g(b,c),g(a,c),d))}function g(a,b){m[a.index]||(m[a.index]=[]);m[b.index]||(m[b.index]=[]);var c=m[a.index][b.index];void 0===c&&(m[a.index][b.index]=m[b.index][a.index]=c=e((new THREE.Vector3).addVectors(a,b).divideScalar(2)));return c}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+0.5,a.y));return a}THREE.Geometry.call(this); +for(var c=c||1,d=d||0,i=this,k=0,l=a.length;k=l){for(k=0;3>k;k++){l=[i[k],i[(k+1)%3]];m=!0;for(n=0;nh;h++)void 0===f[g[h]]&&(f[g[h]]=e++,this.vertices.push(a[g[h]])),g[h]=f[g[h]]}for(d=0;db.y?this.rotation.set(Math.PI,0,0):(a=THREE.ArrowHelper.__v2.set(b.z,0,-b.x).normalize(),b=Math.acos(b.y),a=THREE.ArrowHelper.__q1.setFromAxisAngle(a,b),this.rotation.setEulerFromQuaternion(a,this.eulerOrder))}; +THREE.ArrowHelper.prototype.setLength=function(a){this.scale.set(a,a,a)};THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a);this.cone.material.color.setHex(a)};THREE.ArrowHelper.__v1=new THREE.Vector3;THREE.ArrowHelper.__v2=new THREE.Vector3;THREE.ArrowHelper.__q1=new THREE.Quaternion;THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.geometry.vertices.push(new THREE.Vector3);d.geometry.colors.push(new THREE.Color(b));void 0===d.pointMap[a]&&(d.pointMap[a]=[]);d.pointMap[a].push(d.geometry.vertices.length-1)}THREE.Line.call(this);var d=this;this.geometry=new THREE.Geometry;this.material=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors});this.type=THREE.LinePieces;this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap= +{};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200);b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1", +"cf2",3355443);b("cf3","cf4",3355443);this.camera=a;this.update(a)};THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); +THREE.CameraHelper.prototype.update=function(){function a(a,d,e,f){THREE.CameraHelper.__v.set(d,e,f);THREE.CameraHelper.__projector.unprojectVector(THREE.CameraHelper.__v,THREE.CameraHelper.__c);a=b.pointMap[a];if(void 0!==a){d=0;for(e=a.length;dh.end&&(h.end=f);c||(c=i)}}for(i in d)h=d[i],this.createAnimation(i,h.start,h.end,a);this.firstAnimation=c}; +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; +THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; +THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; +THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; +f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}};THREE.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";b.shaderSource(e,g+a.fragmentShader);b.shaderSource(f,g+a.vertexShader);b.compileShader(e);b.compileShader(f);b.attachShader(d,e);b.attachShader(d,f);b.linkProgram(d);return d}var b,c,d,e,f,g,h,i,k,l,m,n,s;this.init=function(r){b=r.context;c=r;d=r.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);r=0;e[r++]=-1;e[r++]=-1; +e[r++]=0;e[r++]=0;e[r++]=1;e[r++]=-1;e[r++]=1;e[r++]=0;e[r++]=1;e[r++]=1;e[r++]=1;e[r++]=1;e[r++]=-1;e[r++]=1;e[r++]=0;e[r++]=1;r=0;f[r++]=0;f[r++]=1;f[r++]=2;f[r++]=0;f[r++]=2;f[r++]=3;g=b.createBuffer();h=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,g);b.bufferData(b.ARRAY_BUFFER,e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,h);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);i=b.createTexture();k=b.createTexture();b.bindTexture(b.TEXTURE_2D,i);b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16, +0,b.RGB,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.bindTexture(b.TEXTURE_2D,k);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE); +b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);0>=b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)?(l=!1,m=a(THREE.ShaderFlares.lensFlare,d)):(l=!0,m=a(THREE.ShaderFlares.lensFlareVertexTexture,d));n={};s={};n.vertex=b.getAttribLocation(m,"position");n.uv=b.getAttribLocation(m,"uv");s.renderType=b.getUniformLocation(m,"renderType");s.map=b.getUniformLocation(m,"map");s.occlusionMap=b.getUniformLocation(m,"occlusionMap");s.opacity= +b.getUniformLocation(m,"opacity");s.color=b.getUniformLocation(m,"color");s.scale=b.getUniformLocation(m,"scale");s.rotation=b.getUniformLocation(m,"rotation");s.screenPosition=b.getUniformLocation(m,"screenPosition")};this.render=function(a,d,e,f){var a=a.__webglFlares,v=a.length;if(v){var z=new THREE.Vector3,t=f/e,A=0.5*e,I=0.5*f,C=16/f,x=new THREE.Vector2(C*t,C),G=new THREE.Vector3(1,1,0),J=new THREE.Vector2(1,1),E=s,C=n;b.useProgram(m);b.enableVertexAttribArray(n.vertex);b.enableVertexAttribArray(n.uv); +b.uniform1i(E.occlusionMap,0);b.uniform1i(E.map,1);b.bindBuffer(b.ARRAY_BUFFER,g);b.vertexAttribPointer(C.vertex,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(C.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,h);b.disable(b.CULL_FACE);b.depthMask(!1);var H,B,W,F,K;for(H=0;Hx;x++)t[x]=new THREE.Vector3,v[x]=new THREE.Vector3;t=A.shadowCascadeNearZ[z];A=A.shadowCascadeFarZ[z];v[0].set(-1,-1,t);v[1].set(1,-1,t);v[2].set(-1, +1,t);v[3].set(1,1,t);v[4].set(-1,-1,A);v[5].set(1,-1,A);v[6].set(-1,1,A);v[7].set(1,1,A);C.originalCamera=n;v=new THREE.Gyroscope;v.position=p.shadowCascadeOffset;v.add(C);v.add(C.target);n.add(v);p.shadowCascadeArray[y]=C;console.log("Created virtualLight",C)}z=p;t=y;A=z.shadowCascadeArray[t];A.position.copy(z.position);A.target.position.copy(z.target.position);A.lookAt(A.target);A.shadowCameraVisible=z.shadowCameraVisible;A.shadowDarkness=z.shadowDarkness;A.shadowBias=z.shadowCascadeBias[t];v=z.shadowCascadeNearZ[t]; +z=z.shadowCascadeFarZ[t];A=A.pointsFrustum;A[0].z=v;A[1].z=v;A[2].z=v;A[3].z=v;A[4].z=z;A[5].z=z;A[6].z=z;A[7].z=z;I[q]=C;q++}else I[q]=p,q++;s=0;for(r=I.length;sz;z++)t=A[z],t.copy(v[z]),THREE.ShadowMapPlugin.__projector.unprojectVector(t,y),t.applyMatrix4(q.matrixWorldInverse),t.xk.x&&(k.x=t.x),t.yk.y&&(k.y=t.y),t.zk.z&& +(k.z=t.z);q.left=i.x;q.right=k.x;q.top=k.y;q.bottom=i.y;q.updateProjectionMatrix()}q=p.shadowMap;v=p.shadowMatrix;y=p.shadowCamera;y.position.getPositionFromMatrix(p.matrixWorld);l.getPositionFromMatrix(p.target.matrixWorld);y.lookAt(l);y.updateMatrixWorld();y.matrixWorldInverse.getInverse(y.matrixWorld);p.cameraHelper&&(p.cameraHelper.visible=p.shadowCameraVisible);p.shadowCameraVisible&&p.cameraHelper.update();v.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);v.multiply(y.projectionMatrix);v.multiply(y.matrixWorldInverse); +h.multiplyMatrices(y.projectionMatrix,y.matrixWorldInverse);g.setFromMatrix(h);b.setRenderTarget(q);b.clear();A=m.__webglObjects;p=0;for(q=A.length;p 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"}}; diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/ajax_handler.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/ajax_handler.js new file mode 100644 index 000000000..63d536fb6 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/ajax_handler.js @@ -0,0 +1,50 @@ +/* + * 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. + */ +var ajax_handler = function () { + var api = this; + api.response = "v"; + api.ajaxRequest = function (url, type, data, dataType, callback) { + var response; + $.ajax({ + url: url, + type: type, + dataType: dataType, + success: function (data, success) { + api.response = data; + console.log(" success " + JSON.stringify(success)); + console.log(" data " + JSON.stringify(data)); + callback(data, success); + }, + error: function (jqxhr, textStatus, error) { + var err = textStatus + ', ' + error; + console.log("Request Failed: " + err); + callback(data, error); + api.response = data; + }, + data: data + }); + return api.response; + }; + api.makeJSONObject = function () { + var object = {}; + for (var i = 0; i < arguments.length - 1; i = i + 2) { + object[arguments[i]] = arguments[i + 1]; + } + return object; + } +}; \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/general_handler b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/general_handler new file mode 100644 index 000000000..2e8f4b172 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/general_handler @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 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. + */ + +$('.btn-minimize').click(function (e) { + e.preventDefault(); + var $target = $(this).parent().parent().next('.box-content'); + if ($target.is(':visible')) { + $('i', $(this)).removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); + checkAndDisable($(this).parent().attr('id')); + + } + else { + $('i', $(this)).removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); + checkAndEnable($(this).parent().attr('id')); + } + $target.slideToggle(); +}); + +function checkAndEnable(id) { + + //console.log("enable: " + id); + if (id === "RealtimePlotting") { + config_api.modules_status.realtimePlotting = true; + } + else if (id === "SensorReadings") { + config_api.modules_status.sensorReadings = true; + } else if (id === "AngleOfRotation_2") { + config_api.modules_status.angleOfRotation_2 = true; + } else if (id === "AngleOfRotation_1") { + config_api.modules_status.angleOfRotation_1 = true; + } +} + +function checkAndDisable(id) { + //console.log("disable: " + id); + if (id === "RealtimePlotting") { + config_api.modules_status.realtimePlotting = false; + } + else if (id === "SensorReadings") { + config_api.modules_status.sensorReadings = false; + } else if (id === "AngleOfRotation_2") { + config_api.modules_status.angleOfRotation_2 = false; + } else if (id === "AngleOfRotation_1") { + config_api.modules_status.angleOfRotation_1 = false; + } +} + +function isJSON(data) { + try { + return JSON.parse(data); + } + catch (error) { + return null; + } +} + +function Queue() { + var a = [], b = ''; + this.enqueue = function (b) { + a.push([this.getLength() - 1 <= 0 ? 0 : this.getLength() - 1, b]); + }; + this.dequeue = function () { + if (0 != a.length) { + var c = a[b]; + 2 * ++b >= a.length && (a = a.slice(b), b = 0); + return c + } + }; + this.getLength = function () { + return a.length - b; + }; + this.isEmpty = function () { + return 0 == a.length; + }; + + this.peek = function () { + return 0 < a.length ? a[b] : void 0 + }; + this.getData = function () { + return a; + }; + this.make_fixed_size = function (start, end) { + a = a.slice(start, end); + } +} + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/websocket_api b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/websocket_api new file mode 100644 index 000000000..6dc690c6c --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/common/websocket_api @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 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. + */ + + +var webSocket_api = function () { + var api = this; + api.wekSocket; + api.message = function (holder) { + return $("#" + holder + ""); + }, + api.openSocket = function (url, callback) { + if (api.wekSocket !== undefined && api.wekSocket.readyState !== WebSocket.CLOSED) { + console.log("WebSocket is already opened."); + + } else { + api.wekSocket = new WebSocket(url); + } + api.wekSocket.onopen = function (event) { + if (event.data === undefined) + return; + api.writeResponse(event.data); + callback(event.data); + }; + api.wekSocket.onmessage = function (event) { + api.writeResponse(event.data); + }; + + api.wekSocket.onclose = function (event) { + api.writeResponse(event.data); + }; + }, + api.send = function (message) { + api.wekSocket.send(message); + }, + + api.closeSocket = function () { + api.wekSocket.close(); + }, + + api.writeResponse = function (arg) { + console.log(arg); + } +} + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/config/config.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/config/config.js new file mode 100644 index 000000000..fd234991c --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/config/config.js @@ -0,0 +1,37 @@ +/* + * 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. + */ + +var config_api = function () { + var config_api = this; + var context_controller = "/drone_analyzer/controller/send_command"; + config_api.config_3dobject_holder = "#virtualDrone"; + config_api.realtime_plotting_update_interval = 30; + config_api.realtime_plotting_totalPoints = 30; + config_api.realtime_plotting_data_window = {}; + config_api.effectController = {uy: 70.0, uz: 15.0, ux: 10.0, fx: 2.0, fz: 15.0, Tmax: 1}; + config_api.drone_control = context_controller; + config_api.drone_controlType = "POST"; + config_api.drone_controlDataType = "json"; + config_api.web_socket_endpoint = "/drone_analyzer/datastream/drone_status"; + config_api.modules_status = { + "realtimePlotting": false, + "sensorReadings": false, + "angleOfRotation_2": false, + "angleOfRotation_1": false + }; +}; \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/d3.min.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/d3.min.js new file mode 100644 index 000000000..be855941e --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/d3.min.js @@ -0,0 +1,23 @@ +/* + * 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(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function a(n){return n.length}function o(n){for(var t=1;n*t%1;)t*=10;return t}function l(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function c(){this._=Object.create(null)}function s(n){return(n+="")===xa||n[0]===ba?ba+n:n}function f(n){return(n+="")[0]===ba?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=_a.length;r>e;++e){var u=_a[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++ue;e++)for(var u,i=n[e],a=0,o=i.length;o>a;a++)(u=i[a])&&t(u,a,e);return n}function Z(n){return Sa(n,za),n}function V(n){var t,e;return function(r,u,i){var a,o=n[i].update,l=o.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(a=o[t])&&++t0&&(n=n.slice(0,o));var c=La.get(n);return c&&(n=c,l=B),o?t?u:r:t?b:i}function $(n,t){return function(e){var r=oa.event;oa.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{oa.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Ta,u="click"+r,i=oa.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==qa&&(qa="onselectstart"in e?!1:x(e.style,"userSelect")),qa){var a=n(e).style,o=a[qa];a[qa]="none"}return function(n){if(i.on(r,null),qa&&(a[qa]=o),n){var t=function(){i.on(u,null)};i.on(u,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var u=r.createSVGPoint();if(0>Ra){var i=t(n);if(i.scrollX||i.scrollY){r=oa.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var a=r[0][0].getScreenCTM();Ra=!(a.f||a.e),r.remove()}}return Ra?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var o=n.getBoundingClientRect();return[e.clientX-o.left-n.clientLeft,e.clientY-o.top-n.clientTop]}function G(){return oa.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nn(n){return n>1?0:-1>n?ja:Math.acos(n)}function tn(n){return n>1?Ha:-1>n?-Ha:Math.asin(n)}function en(n){return((n=Math.exp(n))-1/n)/2}function rn(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function an(n){return(n=Math.sin(n/2))*n}function on(){}function ln(n,t,e){return this instanceof ln?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ln?new ln(n.h,n.s,n.l):_n(""+n,wn,ln):new ln(n,t,e)}function cn(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(a-i)*n/60:180>n?a:240>n?i+(a-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,a;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,a=.5>=e?e*(1+t):e+t-e*t,i=2*e-a,new yn(u(n+120),u(n),u(n-120))}function sn(n,t,e){return this instanceof sn?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof sn?new sn(n.h,n.c,n.l):n instanceof hn?pn(n.l,n.a,n.b):pn((n=Sn((n=oa.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new sn(n,t,e)}function fn(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(e,Math.cos(n*=Oa)*t,Math.sin(n)*t)}function hn(n,t,e){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof sn?fn(n.h,n.c,n.l):Sn((n=yn(n)).r,n.g,n.b):new hn(n,t,e)}function gn(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=vn(u)*Ka,r=vn(r)*Qa,i=vn(i)*no,new yn(mn(3.2404542*u-1.5371385*r-.4985314*i),mn(-.969266*u+1.8760108*r+.041556*i),mn(.0556434*u-.2040259*r+1.0572252*i))}function pn(n,t,e){return n>0?new sn(Math.atan2(e,t)*Ia,Math.sqrt(t*t+e*e),n):new sn(NaN,NaN,n)}function vn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function mn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function yn(n,t,e){return this instanceof yn?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof yn?new yn(n.r,n.g,n.b):_n(""+n,yn,cn):new yn(n,t,e)}function Mn(n){return new yn(n>>16,n>>8&255,255&n)}function xn(n){return Mn(n)+""}function bn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function _n(n,t,e){var r,u,i,a=0,o=0,l=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(Nn(u[0]),Nn(u[1]),Nn(u[2]))}return(i=ro.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(a=(3840&i)>>4,a=a>>4|a,o=240&i,o=o>>4|o,l=15&i,l=l<<4|l):7===n.length&&(a=(16711680&i)>>16,o=(65280&i)>>8,l=255&i)),t(a,o,l))}function wn(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),a=Math.max(n,t,e),o=a-i,l=(a+i)/2;return o?(u=.5>l?o/(a+i):o/(2-a-i),r=n==a?(t-e)/o+(e>t?6:0):t==a?(e-n)/o+2:(n-t)/o+4,r*=60):(r=NaN,u=l>0&&1>l?0:r),new ln(r,u,l)}function Sn(n,t,e){n=kn(n),t=kn(t),e=kn(e);var r=dn((.4124564*n+.3575761*t+.1804375*e)/Ka),u=dn((.2126729*n+.7151522*t+.072175*e)/Qa),i=dn((.0193339*n+.119192*t+.9503041*e)/no);return hn(116*u-16,500*(r-u),200*(u-i))}function kn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Nn(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function En(n){return"function"==typeof n?n:function(){return n}}function An(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Cn(t,e,n,r)}}function Cn(n,t,e,r){function u(){var n,t=l.status;if(!t&&Ln(l)||t>=200&&300>t||304===t){try{n=e.call(i,l)}catch(r){return void a.error.call(i,r)}a.load.call(i,n)}else a.error.call(i,l)}var i={},a=oa.dispatch("beforesend","progress","load","error"),o={},l=new XMLHttpRequest,c=null;return!this.XDomainRequest||"withCredentials"in l||!/^(http(s)?:)?\/\//.test(n)||(l=new XDomainRequest),"onload"in l?l.onload=l.onerror=u:l.onreadystatechange=function(){l.readyState>3&&u()},l.onprogress=function(n){var t=oa.event;oa.event=n;try{a.progress.call(i,l)}finally{oa.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?o[n]:(null==t?delete o[n]:o[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(c=n,i):c},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ca(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),l.open(e,n,!0),null==t||"accept"in o||(o.accept=t+",*/*"),l.setRequestHeader)for(var s in o)l.setRequestHeader(s,o[s]);return null!=t&&l.overrideMimeType&&l.overrideMimeType(t),null!=c&&(l.responseType=c),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),a.beforesend.call(i,l),l.send(null==r?null:r),i},i.abort=function(){return l.abort(),i},oa.rebind(i,a,"on"),null==r?i:i.get(zn(r))}function zn(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Ln(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qn(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,n:null};return io?io.n=i:uo=i,io=i,ao||(oo=clearTimeout(oo),ao=1,lo(Tn)),i}function Tn(){var n=Rn(),t=Dn()-n;t>24?(isFinite(t)&&(clearTimeout(oo),oo=setTimeout(Tn,t)),ao=0):(ao=1,lo(Tn))}function Rn(){for(var n=Date.now(),t=uo;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Dn(){for(var n,t=uo,e=1/0;t;)t.c?(t.t8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Un(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],a=0,o=r[0],l=0;u>0&&o>0&&(l+o+1>t&&(o=Math.max(1,t-l)),i.push(n.substring(u-=o,u+o)),!((l+=o+1)>t));)o=r[a=(a+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=so.exec(n),r=e[1]||" ",a=e[2]||">",o=e[3]||"-",l=e[4]||"",c=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(c||"0"===r&&"="===a)&&(c=r="0",a="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===l&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===l&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=fo.get(g)||Fn;var M=c&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===o?"":o;if(0>p){var l=oa.formatPrefix(n,h);n=l.scale(n),e=l.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!c&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===a?u+n+k:">"===a?k+u+n:"^"===a?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Fn(n){return n+""}function Hn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function On(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new go(e-1)),1),e}function i(n,e){return t(n=new go(+n),e),n}function a(n,r,i){var a=u(n),o=[];if(i>1)for(;r>a;)e(a)%i||o.push(new Date(+a)),t(a,1);else for(;r>a;)o.push(new Date(+a)),t(a,1);return o}function o(n,t,e){try{go=Hn;var r=new Hn;return r._=n,a(r,t,e)}finally{go=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=a;var l=n.utc=In(n);return l.floor=l,l.round=In(r),l.ceil=In(u),l.offset=In(i),l.range=o,n}function In(n){return function(t,e){try{go=Hn;var r=new Hn;return r._=t,n(r,e)._}finally{go=Date}}}function Yn(n){function t(n){function t(t){for(var e,u,i,a=[],o=-1,l=0;++oo;){if(r>=c)return-1;if(u=t.charCodeAt(o++),37===u){if(a=t.charAt(o++),i=C[a in vo?t.charAt(o++):a],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){N.lastIndex=0;var r=N.exec(t.slice(e));return r?(n.m=E.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,r){return e(n,A.c.toString(),t,r)}function l(n,t,r){return e(n,A.x.toString(),t,r)}function c(n,t,r){return e(n,A.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{go=Hn;var t=new go;return t._=n,r(t)}finally{go=Date}}var r=t(n);return e.parse=function(n){try{go=Hn;var t=r.parse(n);return t&&t._}finally{go=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ct;var M=oa.map(),x=Vn(v),b=Xn(v),_=Vn(d),w=Xn(d),S=Vn(m),k=Xn(m),N=Vn(y),E=Xn(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var A={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return Zn(n.getDate(),t,2)},e:function(n,t){return Zn(n.getDate(),t,2)},H:function(n,t){return Zn(n.getHours(),t,2)},I:function(n,t){return Zn(n.getHours()%12||12,t,2)},j:function(n,t){return Zn(1+ho.dayOfYear(n),t,3)},L:function(n,t){return Zn(n.getMilliseconds(),t,3)},m:function(n,t){return Zn(n.getMonth()+1,t,2)},M:function(n,t){return Zn(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return Zn(n.getSeconds(),t,2)},U:function(n,t){return Zn(ho.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Zn(ho.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return Zn(n.getFullYear()%100,t,2)},Y:function(n,t){return Zn(n.getFullYear()%1e4,t,4)},Z:ot,"%":function(){return"%"}},C={a:r,A:u,b:i,B:a,c:o,d:tt,e:tt,H:rt,I:rt,j:et,L:at,m:nt,M:ut,p:s,S:it,U:Bn,w:$n,W:Wn,x:l,X:c,y:Gn,Y:Jn,Z:Kn,"%":lt};return t}function Zn(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Vn(n){return new RegExp("^(?:"+n.map(oa.requote).join("|")+")","i")}function Xn(n){for(var t=new c,e=-1,r=n.length;++e68?1900:2e3)}function nt(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function tt(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function et(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function rt(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ut(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function it(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function at(n,t,e){mo.lastIndex=0;var r=mo.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ot(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=Ma(t)/60|0,u=Ma(t)%60;return e+Zn(r,"0",2)+Zn(u,"0",2)}function lt(n,t,e){yo.lastIndex=0;var r=yo.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ct(n){for(var t=n.length,e=-1;++e=0?1:-1,o=a*e,l=Math.cos(t),c=Math.sin(t),s=i*c,f=u*l+s*Math.cos(o),h=s*a*Math.sin(o);So.add(Math.atan2(h,f)),r=n,u=l,i=c}var t,e,r,u,i;ko.point=function(a,o){ko.point=n,r=(t=a)*Oa,u=Math.cos(o=(e=o)*Oa/2+ja/4),i=Math.sin(o)},ko.lineEnd=function(){n(t,e)}}function dt(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function mt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function yt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Mt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function bt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function _t(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return Ma(n[0]-t[0])o;++o)u.point((e=n[o])[0],e[1]);return void u.lineEnd()}var l=new Tt(e,n,null,!0),c=new Tt(e,null,l,!1);l.o=c,i.push(l),a.push(c),l=new Tt(r,n,null,!1),c=new Tt(r,null,l,!0),l.o=c,i.push(l),a.push(c)}}),a.sort(t),qt(i),qt(a),i.length){for(var o=0,l=e,c=a.length;c>o;++o)a[o].e=l=!l;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var o=0,c=s.length;c>o;++o)u.point((f=s[o])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var o=s.length-1;o>=0;--o)u.point((f=s[o])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function qt(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r0){for(b||(i.polygonStart(),b=!0),i.lineStart();++a1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Dt))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:a,lineStart:l,lineEnd:c,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=a,y.lineStart=l,y.lineEnd=c,g=oa.merge(g);var n=Ot(m,p);g.length?(b||(i.polygonStart(),b=!0),Lt(g,jt,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Pt(),x=t(M),b=!1;return y}}function Dt(n){return n.length>1}function Pt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function jt(n,t){return((n=n.x)[0]<0?n[1]-Ha-Da:Ha-n[1])-((t=t.x)[0]<0?t[1]-Ha-Da:Ha-t[1])}function Ut(n){var t,e=NaN,r=NaN,u=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(i,a){var o=i>0?ja:-ja,l=Ma(i-e);Ma(l-ja)0?Ha:-Ha),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(o,r),n.point(i,r),t=0):u!==o&&l>=ja&&(Ma(e-u)Da?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*a)):(t+r)/2}function Ht(n,t,e,r){var u;if(null==n)u=e*Ha,r.point(-ja,u),r.point(0,u),r.point(ja,u),r.point(ja,0),r.point(ja,-u),r.point(0,-u),r.point(-ja,-u),r.point(-ja,0),r.point(-ja,u);else if(Ma(n[0]-t[0])>Da){var i=n[0]o;++o){var c=t[o],s=c.length;if(s)for(var f=c[0],h=f[0],g=f[1]/2+ja/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=c[d];var m=n[0],y=n[1]/2+ja/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>ja,k=p*M;if(So.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*Ua:b,S^h>=e^m>=e){var N=yt(dt(f),dt(n));bt(N);var E=yt(u,N);bt(E);var A=(S^b>=0?-1:1)*tn(E[2]);(r>A||r===A&&(N[0]||N[1]))&&(a+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Da>i||Da>i&&0>So)^1&a}function It(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,l,c,s;return{lineStart:function(){c=l=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=a?v?0:u(f,h):v?u(f+(0>f?ja:-ja),h):0;if(!e&&(c=l=v)&&n.lineStart(),v!==l&&(g=r(e,p),(wt(e,g)||wt(p,g))&&(p[0]+=Da,p[1]+=Da,v=t(p[0],p[1]))),v!==l)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(o&&e&&a^v){var m;d&i||!(m=r(p,e,!0))||(s=0,a?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&wt(e,p)||n.point(p[0],p[1]),e=p,l=v,i=d},lineEnd:function(){l&&n.lineEnd(),e=null},clean:function(){return s|(c&&l)<<1}}}function r(n,t,e){var r=dt(n),u=dt(t),a=[1,0,0],o=yt(r,u),l=mt(o,o),c=o[0],s=l-c*c;if(!s)return!e&&n;var f=i*l/s,h=-i*c/s,g=yt(a,o),p=xt(a,f),v=xt(o,h);Mt(p,v);var d=g,m=mt(p,d),y=mt(d,d),M=m*m-y*(mt(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=xt(d,(-m-x)/y);if(Mt(b,p),b=_t(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],N=t[1];w>S&&(_=w,w=S,S=_);var E=S-w,A=Ma(E-ja)E;if(!A&&k>N&&(_=k,k=N,N=_),C?A?k+N>0^b[1]<(Ma(b[0]-w)ja^(w<=b[0]&&b[0]<=S)){var z=xt(d,(-m+x)/y);return Mt(z,p),[b,_t(z)]}}}function u(t,e){var r=a?n:ja-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),a=i>0,o=Ma(i)>Da,l=ve(n,6*Oa);return Rt(t,e,l,a?[0,-n]:[-ja,n-ja])}function Yt(n,t,e,r){return function(u){var i,a=u.a,o=u.b,l=a.x,c=a.y,s=o.x,f=o.y,h=0,g=1,p=s-l,v=f-c;if(i=n-l,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-l,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-c,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-c,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:l+h*p,y:c+h*v}),1>g&&(u.b={x:l+g*p,y:c+g*v}),u}}}}}}function Zt(n,t,e,r){function u(r,u){return Ma(r[0]-n)0?0:3:Ma(r[0]-e)0?2:1:Ma(r[1]-t)0?1:0:u>0?3:2}function i(n,t){return a(n.x,t.x)}function a(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(o){function l(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,a=1,o=d[u],l=o.length,c=o[0];l>a;++a)i=o[a],c[1]<=r?i[1]>r&&Q(c,i,n)>0&&++t:i[1]<=r&&Q(c,i,n)<0&&--t,c=i;return 0!==t}function c(i,o,l,c){var s=0,f=0;if(null==i||(s=u(i,l))!==(f=u(o,l))||a(i,o)<0^l>0){do c.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+l+4)%4)!==f)}else c.point(o[0],o[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&o.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=NaN}function g(){v&&(p(y,M),x&&w&&E.rejoin(),v.push(E.buffer())),C.point=f,w&&o.lineEnd()}function p(n,t){n=Math.max(-Fo,Math.min(Fo,n)),t=Math.max(-Fo,Math.min(Fo,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,M=t,x=e,S=!1,e&&(o.lineStart(),o.point(n,t));else if(e&&w)o.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};A(r)?(w||(o.lineStart(),o.point(r.a.x,r.a.y)),o.point(r.b.x,r.b.y),e||o.lineEnd(),k=!1):e&&(o.lineStart(),o.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,m,y,M,x,b,_,w,S,k,N=o,E=Pt(),A=Yt(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){o=E,v=[],d=[],k=!0},polygonEnd:function(){o=N,v=oa.merge(v);var t=l([n,r]),e=k&&t,u=v.length;(e||u)&&(o.polygonStart(),e&&(o.lineStart(),c(null,null,1,o),o.lineEnd()),u&&Lt(v,i,t,c,o),o.polygonEnd()),v=d=m=null}};return C}}function Vt(n){var t=0,e=ja/3,r=oe(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*ja/180,e=n[1]*ja/180):[t/ja*180,e/ja*180]},u}function Xt(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),a-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),a=Math.sqrt(i)/u;return e.invert=function(n,t){var e=a-t;return[Math.atan2(n,e)/u,tn((i-(n*n+e*e)*u*u)/(2*u))]},e}function $t(){function n(n,t){Oo+=u*n-r*t,r=n,u=t}var t,e,r,u;Xo.point=function(i,a){Xo.point=n,t=r=i,e=u=a},Xo.lineEnd=function(){n(t,e)}}function Bt(n,t){Io>n&&(Io=n),n>Zo&&(Zo=n),Yo>t&&(Yo=t),t>Vo&&(Vo=t)}function Wt(){function n(n,t){a.push("M",n,",",t,i)}function t(n,t){a.push("M",n,",",t),o.point=e}function e(n,t){a.push("L",n,",",t)}function r(){o.point=n}function u(){a.push("Z")}var i=Jt(4.5),a=[],o={point:n,lineStart:function(){o.point=t},lineEnd:r,polygonStart:function(){o.lineEnd=u},polygonEnd:function(){o.lineEnd=r,o.point=n},pointRadius:function(n){return i=Jt(n),o},result:function(){if(a.length){var n=a.join("");return a=[],n}}};return o}function Jt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Gt(n,t){Ao+=n,Co+=t,++zo}function Kt(){function n(n,r){var u=n-t,i=r-e,a=Math.sqrt(u*u+i*i);Lo+=a*(t+n)/2,qo+=a*(e+r)/2,To+=a,Gt(t=n,e=r)}var t,e;Bo.point=function(r,u){Bo.point=n,Gt(t=r,e=u)}}function Qt(){Bo.point=Gt}function ne(){function n(n,t){var e=n-r,i=t-u,a=Math.sqrt(e*e+i*i);Lo+=a*(r+n)/2,qo+=a*(u+t)/2,To+=a,a=u*n-r*t,Ro+=a*(r+n),Do+=a*(u+t),Po+=3*a,Gt(r=n,u=t)}var t,e,r,u;Bo.point=function(i,a){Bo.point=n,Gt(t=r=i,e=u=a)},Bo.lineEnd=function(){n(t,e)}}function te(n){function t(t,e){n.moveTo(t+a,e),n.arc(t,e,a,0,Ua)}function e(t,e){n.moveTo(t,e),o.point=r}function r(t,e){n.lineTo(t,e)}function u(){o.point=t}function i(){n.closePath()}var a=4.5,o={point:t,lineStart:function(){o.point=e},lineEnd:u,polygonStart:function(){o.lineEnd=i},polygonEnd:function(){o.lineEnd=u,o.point=t},pointRadius:function(n){return a=n,o},result:b};return o}function ee(n){function t(n){return(o?r:e)(n)}function e(t){return ie(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=NaN,S.point=i,t.lineStart()}function i(e,r){var i=dt([e,r]),a=n(e,r);u(M,x,y,b,_,w,M=a[0],x=a[1],y=e,b=i[0],_=i[1],w=i[2],o,t),t.point(M,x)}function a(){S.point=e,t.lineEnd()}function l(){r(),S.point=c,S.lineEnd=s}function c(n,t){ +i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,o,t),S.lineEnd=a,a()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:a,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,o,l,c,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=o+g,_=l+p,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=Ma(Ma(w)-1)i||Ma((y*z+M*L)/x-.5)>.3||a>o*g+l*p+c*v)&&(u(t,e,r,o,l,c,A,C,N,b/=S,_/=S,w,d,m),m.point(A,C),u(A,C,N,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,a=Math.cos(30*Oa),o=16;return t.precision=function(n){return arguments.length?(o=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function re(n){var t=ee(function(t,e){return n([t*Ia,e*Ia])});return function(n){return le(t(n))}}function ue(n){this.stream=n}function ie(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ae(n){return oe(function(){return n})()}function oe(n){function t(n){return n=o(n[0]*Oa,n[1]*Oa),[n[0]*h+l,c-n[1]*h]}function e(n){return n=o.invert((n[0]-l)/h,(c-n[1])/h),n&&[n[0]*Ia,n[1]*Ia]}function r(){o=Ct(a=fe(m,M,x),i);var n=i(v,d);return l=g-n[0]*h,c=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,a,o,l,c,s,f=ee(function(n,t){return n=i(n,t),[n[0]*h+l,c-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Uo,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=le(b(a,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Uo):It((w=+n)*Oa),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Zt(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Oa,d=n[1]%360*Oa,r()):[v*Ia,d*Ia]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Oa,M=n[1]%360*Oa,x=n.length>2?n[2]%360*Oa:0,r()):[m*Ia,M*Ia,x*Ia]},oa.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function le(n){return ie(n,function(t,e){n.point(t*Oa,e*Oa)})}function ce(n,t){return[n,t]}function se(n,t){return[n>ja?n-Ua:-ja>n?n+Ua:n,t]}function fe(n,t,e){return n?t||e?Ct(ge(n),pe(t,e)):ge(n):t||e?pe(t,e):se}function he(n){return function(t,e){return t+=n,[t>ja?t-Ua:-ja>t?t+Ua:t,e]}}function ge(n){var t=he(n);return t.invert=he(-n),t}function pe(n,t){function e(n,t){var e=Math.cos(t),o=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),s=c*r+o*u;return[Math.atan2(l*i-s*a,o*r-c*u),tn(s*i+l*a)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),a=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),o=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),s=c*i-l*a;return[Math.atan2(l*i+c*a,o*r+s*u),tn(s*r-o*u)]},e}function ve(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,a,o){var l=a*t;null!=u?(u=de(e,u),i=de(e,i),(a>0?i>u:u>i)&&(u+=a*Ua)):(u=n+a*Ua,i=n-.5*l);for(var c,s=u;a>0?s>i:i>s;s-=l)o.point((c=_t([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],c[1])}}function de(n,t){var e=dt(t);e[0]-=n,bt(e);var r=nn(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Da)%(2*Math.PI)}function me(n,t,e){var r=oa.range(n,t-Da,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function ye(n,t,e){var r=oa.range(n,t-Da,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function Me(n){return n.source}function xe(n){return n.target}function be(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),a=Math.cos(r),o=Math.sin(r),l=u*Math.cos(n),c=u*Math.sin(n),s=a*Math.cos(e),f=a*Math.sin(e),h=2*Math.asin(Math.sqrt(an(r-t)+u*a*an(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*l+t*s,u=e*c+t*f,a=e*i+t*o;return[Math.atan2(u,r)*Ia,Math.atan2(a,Math.sqrt(r*r+u*u))*Ia]}:function(){return[n*Ia,t*Ia]};return p.distance=h,p}function _e(){function n(n,u){var i=Math.sin(u*=Oa),a=Math.cos(u),o=Ma((n*=Oa)-t),l=Math.cos(o);Wo+=Math.atan2(Math.sqrt((o=a*Math.sin(o))*o+(o=r*i-e*a*l)*o),e*i+r*a*l),t=n,e=i,r=a}var t,e,r;Jo.point=function(u,i){t=u*Oa,e=Math.sin(i*=Oa),r=Math.cos(i),Jo.point=n},Jo.lineEnd=function(){Jo.point=Jo.lineEnd=b}}function we(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),a=Math.cos(u);return[Math.atan2(n*i,r*a),Math.asin(r&&e*i/r)]},e}function Se(n,t){function e(n,t){a>0?-Ha+Da>t&&(t=-Ha+Da):t>Ha-Da&&(t=Ha-Da);var e=a/Math.pow(u(t),i);return[e*Math.sin(i*n),a-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(ja/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),a=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=a-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(a/r,1/i))-Ha]},e):Ne}function ke(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return Ma(u)u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function qe(n,t){return n[0]-t[0]||n[1]-t[1]}function Te(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Re(n,t,e,r){var u=n[0],i=e[0],a=t[0]-u,o=r[0]-i,l=n[1],c=e[1],s=t[1]-l,f=r[1]-c,h=(o*(l-c)-f*(u-i))/(f*a-o*s);return[u+h*a,l+h*s]}function De(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Pe(){rr(this),this.edge=this.site=this.circle=null}function je(n){var t=ll.pop()||new Pe;return t.site=n,t}function Ue(n){Be(n),il.remove(n),ll.push(n),rr(n)}function Fe(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,a=n.N,o=[n];Ue(n);for(var l=i;l.circle&&Ma(e-l.circle.x)s;++s)c=o[s],l=o[s-1],nr(c.edge,l.site,c.site,u);l=o[0],c=o[f-1],c.edge=Ke(l.site,c.site,null,u),$e(l),$e(c)}function He(n){for(var t,e,r,u,i=n.x,a=n.y,o=il._;o;)if(r=Oe(o,a)-i,r>Da)o=o.L;else{if(u=i-Ie(o,a),!(u>Da)){r>-Da?(t=o.P,e=o):u>-Da?(t=o,e=o.N):t=e=o;break}if(!o.R){t=o;break}o=o.R}var l=je(n);if(il.insert(t,l),t||e){if(t===e)return Be(t),e=je(t.site),il.insert(l,e),l.edge=e.edge=Ke(t.site,l.site),$e(t),void $e(e);if(!e)return void(l.edge=Ke(t.site,l.site));Be(t),Be(e);var c=t.site,s=c.x,f=c.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};nr(e.edge,c,p,x),l.edge=Ke(c,n,null,x),e.edge=Ke(n,p,null,x),$e(t),$e(e)}}function Oe(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var a=n.P;if(!a)return-(1/0);e=a.site;var o=e.x,l=e.y,c=l-t;if(!c)return o;var s=o-r,f=1/i-1/c,h=s/c;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*c)-l+c/2+u-i/2)))/f+r:(r+o)/2}function Ie(n,t){var e=n.N;if(e)return Oe(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ye(n){this.site=n,this.edges=[]}function Ze(n){for(var t,e,r,u,i,a,o,l,c,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=ul,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(o=i.edges,l=o.length,a=0;l>a;)s=o[a].end(),r=s.x,u=s.y,c=o[++a%l].start(),t=c.x,e=c.y,(Ma(r-t)>Da||Ma(u-e)>Da)&&(o.splice(a,0,new tr(Qe(i.site,s,Ma(r-f)Da?{x:f,y:Ma(t-f)Da?{x:Ma(e-p)Da?{x:h,y:Ma(t-h)Da?{x:Ma(e-g)=-Pa)){var g=l*l+c*c,p=s*s+f*f,v=(f*g-c*p)/h,d=(l*p-s*g)/h,f=d+o,m=cl.pop()||new Xe;m.arc=n,m.site=u,m.x=v+a,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=ol._;M;)if(m.yd||d>=o)return;if(h>p){if(i){if(i.y>=c)return}else i={x:d,y:l};e={x:d,y:c}}else{if(i){if(i.yr||r>1)if(h>p){if(i){if(i.y>=c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else{if(i){if(i.yg){if(i){if(i.x>=o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}else{if(i){if(i.xi||f>a||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(l>m){var y=Math.sqrt(l=m);r=t-y,u=e-y,i=t+y,a=e+y,o=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:c(n,s,f,x,b);break;case 1:c(n,x,f,h,b);break;case 2:c(n,s,b,x,g);break;case 3:c(n,x,b,h,g)}}}(n,r,u,i,a),o}function vr(n,t){n=oa.rgb(n),t=oa.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,a=t.g-r,o=t.b-u;return function(n){return"#"+bn(Math.round(e+i*n))+bn(Math.round(r+a*n))+bn(Math.round(u+o*n))}}function dr(n,t){var e,r={},u={};for(e in n)e in t?r[e]=Mr(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function mr(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function yr(n,t){var e,r,u,i=fl.lastIndex=hl.lastIndex=0,a=-1,o=[],l=[];for(n+="",t+="";(e=fl.exec(n))&&(r=hl.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),o[a]?o[a]+=u:o[++a]=u),(e=e[0])===(r=r[0])?o[a]?o[a]+=r:o[++a]=r:(o[++a]=null,l.push({i:a,x:mr(e,r)})),i=hl.lastIndex;return ir;++r)o[(e=l[r]).i]=e.x(n);return o.join("")})}function Mr(n,t){for(var e,r=oa.interpolators.length;--r>=0&&!(e=oa.interpolators[r](n,t)););return e}function xr(n,t){var e,r=[],u=[],i=n.length,a=t.length,o=Math.min(n.length,t.length);for(e=0;o>e;++e)r.push(Mr(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;a>e;++e)u[e]=t[e];return function(n){for(e=0;o>e;++e)u[e]=r[e](n);return u}}function br(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function _r(n){return function(t){return 1-n(1-t)}}function wr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function Sr(n){return n*n}function kr(n){return n*n*n}function Nr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Er(n){return function(t){return Math.pow(t,n)}}function Ar(n){return 1-Math.cos(n*Ha)}function Cr(n){return Math.pow(2,10*(n-1))}function zr(n){return 1-Math.sqrt(1-n*n)}function Lr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Ua*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Ua/t)}}function qr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Tr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=oa.hcl(n),t=oa.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,a=t.c-r,o=t.l-u;return isNaN(a)&&(a=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return fn(e+i*n,r+a*n,u+o*n)+""}}function Dr(n,t){n=oa.hsl(n),t=oa.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,a=t.s-r,o=t.l-u;return isNaN(a)&&(a=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return cn(e+i*n,r+a*n,u+o*n)+""}}function Pr(n,t){n=oa.lab(n),t=oa.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,a=t.a-r,o=t.b-u;return function(n){return gn(e+i*n,r+a*n,u+o*n)+""}}function jr(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Ur(n){var t=[n.a,n.b],e=[n.c,n.d],r=Hr(t),u=Fr(t,e),i=Hr(Or(e,t,-u))||0;t[0]*e[1]180?t+=360:t-n>180&&(n+=360),r.push({i:e.push(Ir(e)+"rotate(",null,")")-2,x:mr(n,t)})):t&&e.push(Ir(e)+"rotate("+t+")")}function Vr(n,t,e,r){n!==t?r.push({i:e.push(Ir(e)+"skewX(",null,")")-2,x:mr(n,t)}):t&&e.push(Ir(e)+"skewX("+t+")")}function Xr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var u=e.push(Ir(e)+"scale(",null,",",null,")");r.push({i:u-4,x:mr(n[0],t[0])},{i:u-2,x:mr(n[1],t[1])})}else(1!==t[0]||1!==t[1])&&e.push(Ir(e)+"scale("+t+")")}function $r(n,t){var e=[],r=[];return n=oa.transform(n),t=oa.transform(t),Yr(n.translate,t.translate,e,r),Zr(n.rotate,t.rotate,e,r),Vr(n.skew,t.skew,e,r),Xr(n.scale,t.scale,e,r),n=t=null,function(n){for(var t,u=-1,i=r.length;++u=0;)e.push(u[r])}function au(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,a=-1;++ae;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function mu(n){return n.reduce(yu,0)}function yu(n,t){return n+t[1]}function Mu(n,t){return xu(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xu(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function bu(n){return[oa.min(n),oa.max(n)]}function _u(n,t){return n.value-t.value}function wu(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Su(n,t){n._pack_next=t,t._pack_prev=n}function ku(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Nu(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(c=e.length)){var e,r,u,i,a,o,l,c,s=1/0,f=-(1/0),h=1/0,g=-(1/0);if(e.forEach(Eu),r=e[0],r.x=-r.r,r.y=0,t(r),c>1&&(u=e[1],u.x=u.r,u.y=0,t(u),c>2))for(i=e[2],zu(r,u,i),t(i),wu(r,i),r._pack_prev=i,wu(i,u),u=r._pack_next,a=3;c>a;a++){zu(r,u,i=e[a]);var p=0,v=1,d=1;for(o=u._pack_next;o!==u;o=o._pack_next,v++)if(ku(o,i)){p=1;break}if(1==p)for(l=r._pack_prev;l!==o._pack_prev&&!ku(l,i);l=l._pack_prev,d++);p?(d>v||v==d&&u.ra;a++)i=e[a],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(Au)}}function Eu(n){n._pack_next=n._pack_prev=n}function Au(n){delete n._pack_next,delete n._pack_prev}function Cu(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,a=u.length;++i=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Pu(n,t,e){return n.a.parent===t.parent?n.a:e}function ju(n){return 1+oa.max(n,function(n){return n.y})}function Uu(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Fu(n){var t=n.children;return t&&t.length?Fu(t[0]):n}function Hu(n){var t,e=n.children;return e&&(t=e.length)?Hu(e[t-1]):n}function Ou(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Iu(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Yu(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Zu(n){return n.rangeExtent?n.rangeExtent():Yu(n.range())}function Vu(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Xu(n,t){var e,r=0,u=n.length-1,i=n[r],a=n[u];return i>a&&(e=r,r=u,u=e,e=i,i=a,a=e),n[r]=t.floor(i),n[u]=t.ceil(a),n}function $u(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:wl}function Bu(n,t,e,r){var u=[],i=[],a=0,o=Math.min(n.length,t.length)-1;for(n[o]2?Bu:Vu,l=r?Wr:Br;return a=u(n,t,l,e),o=u(t,n,l,Mr),i}function i(n){return a(n)}var a,o;return i.invert=function(n){return o(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(jr)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Qu(n,t)},i.tickFormat=function(t,e){return ni(n,t,e)},i.nice=function(t){return Gu(n,t),u()},i.copy=function(){return Wu(n,t,e,r)},u()}function Ju(n,t){return oa.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Gu(n,t){return Xu(n,$u(Ku(n,t)[2]))}function Ku(n,t){null==t&&(t=10);var e=Yu(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Qu(n,t){return oa.range.apply(oa,Ku(n,t))}function ni(n,t,e){var r=Ku(n,t);if(e){var u=so.exec(e);if(u.shift(),"s"===u[8]){var i=oa.formatPrefix(Math.max(Ma(r[0]),Ma(r[1])));return u[7]||(u[7]="."+ti(i.scale(r[2]))),u[8]="f",e=oa.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+ei(u[8],r)),e=u.join("")}else e=",."+ti(r[2])+"f";return oa.format(e)}function ti(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function ei(n,t){var e=ti(t[2]);return n in Sl?Math.abs(e-ti(Math.max(Ma(t[0]),Ma(t[1]))))+ +("e"!==n):e-2*("%"===n)}function ri(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function a(t){return n(u(t))}return a.invert=function(t){return i(n.invert(t))},a.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),a):r},a.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),a):t},a.nice=function(){var t=Xu(r.map(u),e?Math:Nl);return n.domain(t),r=t.map(i),a},a.ticks=function(){var n=Yu(r),a=[],o=n[0],l=n[1],c=Math.floor(u(o)),s=Math.ceil(u(l)),f=t%1?2:t;if(isFinite(s-c)){if(e){for(;s>c;c++)for(var h=1;f>h;h++)a.push(i(c)*h);a.push(i(c))}else for(a.push(i(c));c++0;h--)a.push(i(c)*h);for(c=0;a[c]l;s--);a=a.slice(c,s)}return a},a.tickFormat=function(n,t){if(!arguments.length)return kl;arguments.length<2?t=kl:"function"!=typeof t&&(t=oa.format(t));var r,o=Math.max(.1,n/a.ticks().length),l=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(l(u(n)+r))<=o?t(n):""}},a.copy=function(){return ri(n.copy(),t,e,r)},Ju(a,n)}function ui(n,t,e){function r(t){return n(u(t))}var u=ii(t),i=ii(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Qu(e,n)},r.tickFormat=function(n,t){return ni(e,n,t)},r.nice=function(n){return r.domain(Gu(e,n))},r.exponent=function(a){return arguments.length?(u=ii(t=a),i=ii(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return ui(n.copy(),t,e)},Ju(r,n)}function ii(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ai(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):NaN))-1)%i.length]}function r(t,e){return oa.range(n.length).map(function(n){return t+e*n})}var u,i,a;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new c;for(var i,a=-1,o=r.length;++ae?[NaN,NaN]:[e>0?o[e-1]:n[0],et?NaN:t/i+n,[t,t+1/i]},r.copy=function(){return li(n,t,e)},u()}function ci(n,t){function e(e){return e>=e?t[oa.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return ci(n,t)},e}function si(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Qu(n,t)},t.tickFormat=function(t,e){return ni(n,t,e)},t.copy=function(){return si(n)},t}function fi(){return 0}function hi(n){return n.innerRadius}function gi(n){return n.outerRadius}function pi(n){return n.startAngle}function vi(n){return n.endAngle}function di(n){return n&&n.padAngle}function mi(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function yi(n,t,e,r,u){var i=n[0]-t[0],a=n[1]-t[1],o=(u?r:-r)/Math.sqrt(i*i+a*a),l=o*a,c=-o*i,s=n[0]+l,f=n[1]+c,h=t[0]+l,g=t[1]+c,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(Math.max(0,M*M*y-x*x)),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,N=_-p,E=w-v,A=S-p,C=k-v;return N*N+E*E>A*A+C*C&&(_=S,w=k),[[_-l,w-c],[_*e/M,w*e/M]]}function Mi(n){function t(t){function a(){c.push("M",i(n(s),o))}for(var l,c=[],s=[],f=-1,h=t.length,g=En(e),p=En(r);++f1?n.join("L"):n+"Z"}function bi(n){return n.join("L")+"Z"}function _i(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t1&&u.push("H",r[0]),u.join("")}function wi(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t1){o=t[1],i=n[l],l++,r+="C"+(u[0]+a[0])+","+(u[1]+a[1])+","+(i[0]-o[0])+","+(i[1]-o[1])+","+i[0]+","+i[1];for(var c=2;c9&&(u=3*t/Math.sqrt(u),a[o]=u*e,a[o+1]=u*r));for(o=-1;++o<=l;)u=(n[Math.min(l,o+1)][0]-n[Math.max(0,o-1)][0])/(6*(1+a[o]*a[o])),i.push([u||0,a[o]*u||0]);return i}function Fi(n){return n.length<3?xi(n):n[0]+Ai(n,Ui(n))}function Hi(n){for(var t,e,r,u=-1,i=n.length;++u=t?a(n-t):void(s.c=a)}function a(e){var u=p.active,i=p[u];i&&(i.timer.c=null,i.timer.t=NaN,--p.count,delete p[u],i.event&&i.event.interrupt.call(n,n.__data__,i.index));for(var a in p)if(r>+a){var c=p[a];c.timer.c=null,c.timer.t=NaN,--p.count,delete p[a]}s.c=o,qn(function(){return s.c&&o(e||1)&&(s.c=null,s.t=NaN),1},0,l),p.active=r,v.event&&v.event.start.call(n,n.__data__,t),g=[],v.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&g.push(r)}),h=v.ease,f=v.duration}function o(u){for(var i=u/f,a=h(i),o=g.length;o>0;)g[--o].call(n,a);return i>=1?(v.event&&v.event.end.call(n,n.__data__,t),--p.count?delete p[r]:delete n[e],1):void 0}var l,s,f,h,g,p=n[e]||(n[e]={active:0,count:0}),v=p[r];v||(l=u.time,s=qn(i,0,l),v=p[r]={tween:new c,time:l,timer:s,delay:u.delay,duration:u.duration,ease:u.ease,index:t},u=null,++p.count)}function na(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function ta(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function ea(n){return n.toISOString()}function ra(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=oa.bisect(Gl,u);return i==Gl.length?[t.year,Ku(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Gl[i-1]1?{floor:function(t){for(;e(t=n.floor(t));)t=ua(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=ua(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Yu(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],ua(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return ra(n.copy(),t,e)},Ju(r,n)}function ua(n){return new Date(n)}function ia(n){return JSON.parse(n.responseText)}function aa(n){var t=sa.createRange();return t.selectNode(sa.body),t.createContextualFragment(n.responseText)}var oa={version:"3.5.10"},la=[].slice,ca=function(n){return la.call(n)},sa=this.document;if(sa)try{ca(sa.documentElement.childNodes)[0].nodeType}catch(fa){ca=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),sa)try{sa.createElement("DIV").style.setProperty("opacity",0,"")}catch(ha){var ga=this.Element.prototype,pa=ga.setAttribute,va=ga.setAttributeNS,da=this.CSSStyleDeclaration.prototype,ma=da.setProperty;ga.setAttribute=function(n,t){pa.call(this,n,t+"")},ga.setAttributeNS=function(n,t,e){va.call(this,n,t,e+"")},da.setProperty=function(n,t,e){ma.call(this,n,t+"",e)}}oa.ascending=e,oa.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},oa.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=r){e=r;break}for(;++ur&&(e=r)}else{for(;++u=r){e=r;break}for(;++ur&&(e=r)}return e},oa.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=r){e=r;break}for(;++ue&&(e=r)}else{for(;++u=r){e=r;break}for(;++ue&&(e=r)}return e},oa.extent=function(n,t){var e,r,u,i=-1,a=n.length;if(1===arguments.length){for(;++i=r){e=u=r;break}for(;++ir&&(e=r),r>u&&(u=r))}else{for(;++i=r){e=u=r;break}for(;++ir&&(e=r),r>u&&(u=r))}return[e,u]},oa.sum=function(n,t){var e,r=0,i=n.length,a=-1;if(1===arguments.length)for(;++a1?l/(s-1):void 0},oa.deviation=function(){var n=oa.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ya=i(e);oa.bisectLeft=ya.left,oa.bisect=oa.bisectRight=ya.right,oa.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},oa.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},oa.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},oa.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},oa.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=oa.min(arguments,a),e=new Array(t);++n=0;)for(r=n[u],t=r.length;--t>=0;)e[--a]=r[t];return e};var Ma=Math.abs;oa.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,u=[],i=o(Ma(e)),a=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++a)>t;)u.push(r/i);else for(;(r=n+e*++a)=i.length)return r?r.call(u,a):e?a.sort(e):a;for(var l,s,f,h,g=-1,p=a.length,v=i[o++],d=new c;++g=i.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],a=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(oa.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return a[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},oa.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),oa.behavior={},oa.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},oa.event=null,oa.requote=function(n){return n.replace(wa,"\\$&")};var wa=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,Sa={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},ka=function(n,t){return t.querySelector(n)},Na=function(n,t){return t.querySelectorAll(n)},Ea=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(Ea=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(ka=function(n,t){return Sizzle(n,t)[0]||null},Na=Sizzle,Ea=Sizzle.matchesSelector),oa.selection=function(){return oa.select(sa.documentElement)};var Aa=oa.selection.prototype=[];Aa.select=function(n){var t,e,r,u,i=[];n=A(n);for(var a=-1,o=this.length;++a=0&&"xmlns"!==(e=n.slice(0,t))&&(n=n.slice(t+1)),Ca.hasOwnProperty(e)?{space:Ca[e],local:n}:n}},Aa.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=oa.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},Aa.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++uu){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},Aa.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(j(t,n[t]));return this}return this.each(j(n,t))},Aa.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Aa.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Aa.append=function(n){return n=U(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Aa.insert=function(n,t){return n=U(n),t=A(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},Aa.remove=function(){return this.each(F)},Aa.data=function(n,t){function e(n,e){var r,u,i,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),v=new Array(a);if(t){var d,m=new c,y=new Array(a);for(r=-1;++rr;++r)p[r]=H(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,o.push(p),l.push(g),s.push(v)}var r,u,i=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++ii;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var o=0,l=e.length;l>o;o++)(r=e[o])&&n.call(r,r.__data__,o,i)&&t.push(r)}return E(u)},Aa.order=function(){for(var n=-1,t=this.length;++n=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},Aa.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++tn;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},Aa.size=function(){var n=0;return Y(this,function(){++n}),n};var za=[];oa.selection.enter=Z,oa.selection.enter.prototype=za,za.append=Aa.append,za.empty=Aa.empty,za.node=Aa.node,za.call=Aa.call,za.size=Aa.size,za.select=function(n){for(var t,e,r,u,i,a=[],o=-1,l=this.length;++or){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var La=oa.map({mouseenter:"mouseover",mouseleave:"mouseout"});sa&&La.forEach(function(n){"on"+n in sa&&La.remove(n)});var qa,Ta=0;oa.mouse=function(n){return J(n,k())};var Ra=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;oa.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},oa.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",a)}function e(n,t,e,i,a){return function(){function o(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+c[0],y:r[1]+c[1],dx:n,dy:e}))}function l(){t(h,v)&&(m.on(i+d,null).on(a+d,null),y(p),g({type:"dragend"}))}var c,s=this,f=oa.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=oa.select(e(f)).on(i+d,o).on(a+d,l),y=W(f),M=t(h,v);u?(c=u.apply(s,arguments),c=[c.x-M[0],c.y-M[1]]):c=[0,0],g({type:"dragstart"})}}var r=N(n,"drag","dragstart","dragend"),u=null,i=e(b,oa.mouse,t,"mousemove","mouseup"),a=e(G,oa.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},oa.rebind(n,r,"on")},oa.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ca(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Da=1e-6,Pa=Da*Da,ja=Math.PI,Ua=2*ja,Fa=Ua-Da,Ha=ja/2,Oa=ja/180,Ia=180/ja,Ya=Math.SQRT2,Za=2,Va=4;oa.interpolateZoom=function(n,t){var e,r,u=n[0],i=n[1],a=n[2],o=t[0],l=t[1],c=t[2],s=o-u,f=l-i,h=s*s+f*f;if(Pa>h)r=Math.log(c/a)/Ya,e=function(n){return[u+n*s,i+n*f,a*Math.exp(Ya*n*r)]};else{var g=Math.sqrt(h),p=(c*c-a*a+Va*h)/(2*a*Za*g),v=(c*c-a*a-Va*h)/(2*c*Za*g),d=Math.log(Math.sqrt(p*p+1)-p),m=Math.log(Math.sqrt(v*v+1)-v);r=(m-d)/Ya,e=function(n){var t=n*r,e=rn(d),o=a/(Za*g)*(e*un(Ya*t+d)-en(d));return[u+o*s,i+o*f,a*e/rn(Ya*t+d)]}}return e.duration=1e3*r,e},oa.behavior.zoom=function(){function n(n){n.on(L,f).on($a+".zoom",g).on("dblclick.zoom",p).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function u(n){k.k=Math.max(A[0],Math.min(A[1],n))}function i(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function a(t,e,r,a){t.__chart__={x:k.x,y:k.y,k:k.k},u(Math.pow(2,a)),i(d=e,r),t=oa.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function o(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function l(n){z++||n({type:"zoomstart"})}function c(n){o(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||(n({type:"zoomend"}),d=null)}function f(){function n(){o=1,i(oa.mouse(u),h),c(a)}function r(){f.on(q,null).on(T,null),g(o),s(a)}var u=this,a=D.of(u,arguments),o=0,f=oa.select(t(u)).on(q,n).on(T,r),h=e(oa.mouse(u)),g=W(u);Ol.call(u),l(a)}function h(){function n(){var n=oa.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=oa.event.target;oa.select(t).on(x,r).on(b,o),_.push(t);for(var e=oa.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var l=n(),c=Date.now();if(1===l.length){if(500>c-M){var s=l[0];a(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=c}else if(l.length>1){var s=l[0],f=l[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,a=oa.touches(p);Ol.call(p);for(var o=0,l=a.length;l>o;++o,r=null)if(e=a[o],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),c(v)}function o(){if(oa.event.touches.length){for(var t=oa.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}oa.selectAll(_).on(y,null),w.on(L,f).on(R,h),N(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+oa.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=oa.select(p),N=W(p);t(),l(v),w.on(L,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(Ol.call(this),v=e(d=m||oa.mouse(this)),l(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Xa())*k.k),i(d,v),c(n)}function p(){var n=oa.mouse(this),t=Math.log(k.k)/Math.LN2;a(this,n,e(n),oa.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},E=[960,500],A=Ba,C=250,z=0,L="mousedown.zoom",q="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=N(n,"zoomstart","zoom","zoomend");return $a||($a="onwheel"in sa?(Xa=function(){return-oa.event.deltaY*(oa.event.deltaMode?120:1)},"wheel"):"onmousewheel"in sa?(Xa=function(){return oa.event.wheelDelta},"mousewheel"):(Xa=function(){return-oa.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Fl?oa.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},l(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],u=d?d[0]:e/2,i=d?d[1]:r/2,a=oa.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=a(t),o=e/r[2];this.__chart__=k={x:u-r[0]*o,y:i-r[1]*o,k:o},c(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,l(n),c(n),s(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},o(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:null},u(+t),o(),n):k.k},n.scaleExtent=function(t){return arguments.length?(A=null==t?Ba:[+t[0],+t[1]],n):A},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},oa.rebind(n,D,"on")};var Xa,$a,Ba=[0,1/0];oa.color=on,on.prototype.toString=function(){return this.rgb()+""},oa.hsl=ln;var Wa=ln.prototype=new on;Wa.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,this.l/n)},Wa.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,n*this.l)},Wa.rgb=function(){return cn(this.h,this.s,this.l)},oa.hcl=sn;var Ja=sn.prototype=new on;Ja.brighter=function(n){return new sn(this.h,this.c,Math.min(100,this.l+Ga*(arguments.length?n:1)))},Ja.darker=function(n){return new sn(this.h,this.c,Math.max(0,this.l-Ga*(arguments.length?n:1)))},Ja.rgb=function(){return fn(this.h,this.c,this.l).rgb()},oa.lab=hn;var Ga=18,Ka=.95047,Qa=1,no=1.08883,to=hn.prototype=new on;to.brighter=function(n){return new hn(Math.min(100,this.l+Ga*(arguments.length?n:1)),this.a,this.b)},to.darker=function(n){return new hn(Math.max(0,this.l-Ga*(arguments.length?n:1)),this.a,this.b)},to.rgb=function(){return gn(this.l,this.a,this.b)},oa.rgb=yn;var eo=yn.prototype=new on;eo.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new yn(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new yn(u,u,u)},eo.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new yn(n*this.r,n*this.g,n*this.b)},eo.hsl=function(){return wn(this.r,this.g,this.b)},eo.toString=function(){return"#"+bn(this.r)+bn(this.g)+bn(this.b)};var ro=oa.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ro.forEach(function(n,t){ro.set(n,Mn(t))}),oa.functor=En,oa.xhr=An(y),oa.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var a=Cn(n,t,null==e?r:u(e),i);return a.row=function(n){return arguments.length?a.response(null==(e=n)?r:u(n)):e},a}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(a).join(n)}function a(n){return o.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var o=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=c)return a;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++s;){var r=n.charCodeAt(s++),o=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++o);else if(r!==l)continue;return n.slice(t,s-o)}return n.slice(t)}for(var r,u,i={},a={},o=[],c=n.length,s=0,f=0;(r=e())!==a;){for(var h=[];r!==i&&r!==a;)h.push(r),r=e();t&&null==(h=t(h,f++))||o.push(h)}return o},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(a).join(n)].concat(t.map(function(t){return u.map(function(n){return a(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},oa.csv=oa.dsv(",","text/csv"),oa.tsv=oa.dsv(" ","text/tab-separated-values");var uo,io,ao,oo,lo=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};oa.timer=function(){qn.apply(this,arguments)},oa.timer.flush=function(){Rn(),Dn()},oa.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var co=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(jn);oa.formatPrefix=function(n,t){var e=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=oa.round(n,Pn(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),co[8+e/3]};var so=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,fo=oa.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=oa.round(n,Pn(n,t))).toFixed(Math.max(0,Math.min(20,Pn(n*(1+1e-15),t))))}}),ho=oa.time={},go=Date;Hn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){po.setUTCDate.apply(this._,arguments)},setDay:function(){po.setUTCDay.apply(this._,arguments)},setFullYear:function(){po.setUTCFullYear.apply(this._,arguments)},setHours:function(){po.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){po.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){po.setUTCMinutes.apply(this._,arguments)},setMonth:function(){po.setUTCMonth.apply(this._,arguments)},setSeconds:function(){po.setUTCSeconds.apply(this._,arguments)},setTime:function(){po.setTime.apply(this._,arguments)}};var po=Date.prototype;ho.year=On(function(n){return n=ho.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ho.years=ho.year.range,ho.years.utc=ho.year.utc.range,ho.day=On(function(n){var t=new go(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ho.days=ho.day.range,ho.days.utc=ho.day.utc.range,ho.dayOfYear=function(n){var t=ho.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ho[n]=On(function(n){return(n=ho.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ho.year(n).getDay();return Math.floor((ho.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ho[n+"s"]=e.range,ho[n+"s"].utc=e.utc.range,ho[n+"OfYear"]=function(n){var e=ho.year(n).getDay();return Math.floor((ho.dayOfYear(n)+(e+t)%7)/7)}}),ho.week=ho.sunday,ho.weeks=ho.sunday.range,ho.weeks.utc=ho.sunday.utc.range,ho.weekOfYear=ho.sundayOfYear;var vo={"-":"",_:" ",0:"0"},mo=/^\s*\d+/,yo=/^%/;oa.locale=function(n){return{numberFormat:Un(n),timeFormat:Yn(n)}};var Mo=oa.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], +shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});oa.format=Mo.numberFormat,oa.geo={},st.prototype={s:0,t:0,add:function(n){ft(n,this.t,xo),ft(xo.s,this.s,this),this.s?this.t+=xo.t:this.s=xo.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var xo=new st;oa.geo.stream=function(n,t){n&&bo.hasOwnProperty(n.type)?bo[n.type](n,t):ht(n,t)};var bo={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++rn?4*ja+n:n,ko.lineStart=ko.lineEnd=ko.point=b}};oa.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=dt([t*Oa,e*Oa]);if(m){var u=yt(m,r),i=[u[1],-u[0],0],a=yt(i,u);bt(a),a=_t(a);var l=t-p,c=l>0?1:-1,v=a[0]*Ia*c,d=Ma(l)>180;if(d^(v>c*p&&c*t>v)){var y=a[1]*Ia;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>c*p&&c*t>v)){var y=-a[1]*Ia;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?o(s,t)>o(s,h)&&(h=t):o(t,h)>o(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?o(s,t)>o(s,h)&&(h=t):o(t,h)>o(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=Ma(r)>180?r+(r>0?360:-360):r}else v=n,d=e;ko.point(n,e),t(n,e)}function i(){ko.lineStart()}function a(){u(v,d),ko.lineEnd(),Ma(y)>Da&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function o(n,t){return(t-=n)<0?t+360:t}function l(n,t){return n[0]-t[0]}function c(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nSo?(s=-(h=180),f=-(g=90)):y>Da?g=90:-Da>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],oa.geo.stream(n,b);var t=M.length;if(t){M.sort(l);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],c(e[0],u)||c(e[1],u)?(o(u[0],e[1])>o(u[0],u[1])&&(u[1]=e[1]),o(e[0],u[1])>o(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var a,e,p=-(1/0),t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(a=o(u[1],e[0]))>p&&(p=a,s=e[0],h=u[1])}return M=x=null,s===1/0||f===1/0?[[NaN,NaN],[NaN,NaN]]:[[s,f],[h,g]]}}(),oa.geo.centroid=function(n){No=Eo=Ao=Co=zo=Lo=qo=To=Ro=Do=Po=0,oa.geo.stream(n,jo);var t=Ro,e=Do,r=Po,u=t*t+e*e+r*r;return Pa>u&&(t=Lo,e=qo,r=To,Da>Eo&&(t=Ao,e=Co,r=zo),u=t*t+e*e+r*r,Pa>u)?[NaN,NaN]:[Math.atan2(e,t)*Ia,tn(r/Math.sqrt(u))*Ia]};var No,Eo,Ao,Co,zo,Lo,qo,To,Ro,Do,Po,jo={sphere:b,point:St,lineStart:Nt,lineEnd:Et,polygonStart:function(){jo.lineStart=At},polygonEnd:function(){jo.lineStart=Nt}},Uo=Rt(zt,Ut,Ht,[-ja,-ja/2]),Fo=1e9;oa.geo.clipExtent=function(){var n,t,e,r,u,i,a={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(o){return arguments.length?(i=Zt(n=+o[0][0],t=+o[0][1],e=+o[1][0],r=+o[1][1]),u&&(u.valid=!1,u=null),a):[[n,t],[e,r]]}};return a.extent([[0,0],[960,500]])},(oa.geo.conicEqualArea=function(){return Vt(Xt)}).raw=Xt,oa.geo.albers=function(){return oa.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},oa.geo.albersUsa=function(){function n(n){var i=n[0],a=n[1];return t=null,e(i,a),t||(r(i,a),t)||u(i,a),t}var t,e,r,u,i=oa.geo.albers(),a=oa.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),o=oa.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?a:u>=.166&&.234>u&&r>=-.214&&-.115>r?o:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=a.stream(n),r=o.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),a.precision(t),o.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),a.scale(.35*t),o.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var c=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*c,f-.238*c],[s+.455*c,f+.238*c]]).stream(l).point,r=a.translate([s-.307*c,f+.201*c]).clipExtent([[s-.425*c+Da,f+.12*c+Da],[s-.214*c-Da,f+.234*c-Da]]).stream(l).point,u=o.translate([s-.205*c,f+.212*c]).clipExtent([[s-.214*c+Da,f+.166*c+Da],[s-.115*c-Da,f+.234*c-Da]]).stream(l).point,n},n.scale(1070)};var Ho,Oo,Io,Yo,Zo,Vo,Xo={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Oo=0,Xo.lineStart=$t},polygonEnd:function(){Xo.lineStart=Xo.lineEnd=Xo.point=b,Ho+=Ma(Oo/2)}},$o={point:Bt,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Bo={point:Gt,lineStart:Kt,lineEnd:Qt,polygonStart:function(){Bo.lineStart=ne},polygonEnd:function(){Bo.point=Gt,Bo.lineStart=Kt,Bo.lineEnd=Qt}};oa.geo.path=function(){function n(n){return n&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),a&&a.valid||(a=u(i)),oa.geo.stream(n,a)),i.result()}function t(){return a=null,n}var e,r,u,i,a,o=4.5;return n.area=function(n){return Ho=0,oa.geo.stream(n,u(Xo)),Ho},n.centroid=function(n){return Ao=Co=zo=Lo=qo=To=Ro=Do=Po=0,oa.geo.stream(n,u(Bo)),Po?[Ro/Po,Do/Po]:To?[Lo/To,qo/To]:zo?[Ao/zo,Co/zo]:[NaN,NaN]},n.bounds=function(n){return Zo=Vo=-(Io=Yo=1/0),oa.geo.stream(n,u($o)),[[Io,Yo],[Zo,Vo]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||re(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new Wt:new te(n),"function"!=typeof o&&i.pointRadius(o),t()):r},n.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),n):o},n.projection(oa.geo.albersUsa()).context(null)},oa.geo.transform=function(n){return{stream:function(t){var e=new ue(t);for(var r in n)e[r]=n[r];return e}}},ue.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},oa.geo.projection=ae,oa.geo.projectionMutator=oe,(oa.geo.equirectangular=function(){return ae(ce)}).raw=ce.invert=ce,oa.geo.rotation=function(n){function t(t){return t=n(t[0]*Oa,t[1]*Oa),t[0]*=Ia,t[1]*=Ia,t}return n=fe(n[0]%360*Oa,n[1]*Oa,n.length>2?n[2]*Oa:0),t.invert=function(t){return t=n.invert(t[0]*Oa,t[1]*Oa),t[0]*=Ia,t[1]*=Ia,t},t},se.invert=ce,oa.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=fe(-n[0]*Oa,-n[1]*Oa,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ia,n[1]*=Ia}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=ve((t=+r)*Oa,u*Oa),n):t},n.precision=function(r){return arguments.length?(e=ve(t*Oa,(u=+r)*Oa),n):u},n.angle(90)},oa.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Oa,u=n[1]*Oa,i=t[1]*Oa,a=Math.sin(r),o=Math.cos(r),l=Math.sin(u),c=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*a)*e+(e=c*s-l*f*o)*e),l*s+c*f*o)},oa.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return oa.range(Math.ceil(i/d)*d,u,d).map(h).concat(oa.range(Math.ceil(c/m)*m,l,m).map(g)).concat(oa.range(Math.ceil(r/p)*p,e,p).filter(function(n){return Ma(n%d)>Da}).map(s)).concat(oa.range(Math.ceil(o/v)*v,a,v).filter(function(n){return Ma(n%m)>Da}).map(f))}var e,r,u,i,a,o,l,c,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(l).slice(1),h(u).reverse().slice(1),g(c).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],c=+t[0][1],l=+t[1][1],i>u&&(t=i,i=u,u=t),c>l&&(t=c,c=l,l=t),n.precision(y)):[[i,c],[u,l]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],o=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),o>a&&(t=o,o=a,a=t),n.precision(y)):[[r,o],[e,a]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=me(o,a,90),f=ye(r,e,y),h=me(c,l,90),g=ye(i,u,y),n):y},n.majorExtent([[-180,-90+Da],[180,90-Da]]).minorExtent([[-180,-80-Da],[180,80+Da]])},oa.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=Me,u=xe;return n.distance=function(){return oa.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},oa.geo.interpolate=function(n,t){return be(n[0]*Oa,n[1]*Oa,t[0]*Oa,t[1]*Oa)},oa.geo.length=function(n){return Wo=0,oa.geo.stream(n,Jo),Wo};var Wo,Jo={sphere:b,point:b,lineStart:_e,lineEnd:b,polygonStart:b,polygonEnd:b},Go=we(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(oa.geo.azimuthalEqualArea=function(){return ae(Go)}).raw=Go;var Ko=we(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(oa.geo.azimuthalEquidistant=function(){return ae(Ko)}).raw=Ko,(oa.geo.conicConformal=function(){return Vt(Se)}).raw=Se,(oa.geo.conicEquidistant=function(){return Vt(ke)}).raw=ke;var Qo=we(function(n){return 1/n},Math.atan);(oa.geo.gnomonic=function(){return ae(Qo)}).raw=Qo,Ne.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ha]},(oa.geo.mercator=function(){return Ee(Ne)}).raw=Ne;var nl=we(function(){return 1},Math.asin);(oa.geo.orthographic=function(){return ae(nl)}).raw=nl;var tl=we(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(oa.geo.stereographic=function(){return ae(tl)}).raw=tl,Ae.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ha]},(oa.geo.transverseMercator=function(){var n=Ee(Ae),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Ae,oa.geom={},oa.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=En(e),i=En(r),a=n.length,o=[],l=[];for(t=0;a>t;t++)o.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(o.sort(qe),t=0;a>t;t++)l.push([o[t][0],-o[t][1]]);var c=Le(o),s=Le(l),f=s[0]===c[0],h=s[s.length-1]===c[c.length-1],g=[];for(t=c.length-1;t>=0;--t)g.push(n[o[c[t]][2]]);for(t=+f;t=r&&c.x<=i&&c.y>=u&&c.y<=a?[[r,a],[i,a],[i,u],[r,u]]:[];s.point=n[o]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Da)*Da,y:Math.round(a(n,t)/Da)*Da,i:t}})}var r=Ce,u=ze,i=r,a=u,o=sl;return n?t(n):(t.links=function(n){return or(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return or(e(n)).cells.forEach(function(e,r){for(var u,i,a=e.site,o=e.edges.sort(Ve),l=-1,c=o.length,s=o[c-1].edge,f=s.l===a?s.r:s.l;++l=c,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=hr()),f?u=c:o=c,h?a=s:l=s,i(n,t,e,r,u,a,o,l)}var s,f,h,g,p,v,d,m,y,M=En(o),x=En(l);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,a)for(g=0;p>g;++g)s=n[g],s.xm&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=hr();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){gr(n,k,v,d,m,y)},k.find=function(n){return pr(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=pl.get(e)||gl,r=vl.get(r)||y,br(r(e.apply(null,la.call(arguments,1))))},oa.interpolateHcl=Rr,oa.interpolateHsl=Dr,oa.interpolateLab=Pr,oa.interpolateRound=jr,oa.transform=function(n){var t=sa.createElementNS(oa.ns.prefix.svg,"g");return(oa.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Ur(e?e.matrix:dl)})(n)},Ur.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var dl={a:1,b:0,c:0,d:1,e:0,f:0};oa.interpolateTransform=$r,oa.layout={},oa.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++eo*o/m){if(v>l){var c=t.charge/l;n.px-=i*c,n.py-=a*c}return!0}if(t.point&&l&&v>l){var c=t.pointCharge/l;n.px-=i*c,n.py-=a*c}}return!t.charge}}function t(n){n.px=oa.event.x,n.py=oa.event.y,l.resume()}var e,r,u,i,a,o,l={},c=oa.dispatch("start","tick","end"),s=[1,1],f=.9,h=ml,g=yl,p=-30,v=Ml,d=.1,m=.64,M=[],x=[];return l.tick=function(){if((u*=.99)<.005)return e=null,c.end({type:"end",alpha:u=0}),!0;var t,r,l,h,g,v,m,y,b,_=M.length,w=x.length;for(r=0;w>r;++r)l=x[r],h=l.source,g=l.target,y=g.x-h.x,b=g.y-h.y,(v=y*y+b*b)&&(v=u*a[r]*((v=Math.sqrt(v))-i[r])/v,y*=v,b*=v,g.x-=y*(m=h.weight+g.weight?h.weight/(h.weight+g.weight):.5),g.y-=b*m,h.x+=y*(m=1-m),h.y+=b*m);if((m=u*d)&&(y=s[0]/2,b=s[1]/2,r=-1,m))for(;++r<_;)l=M[r],l.x+=(y-l.x)*m,l.y+=(b-l.y)*m;if(p)for(ru(t=oa.geom.quadtree(M),u,o),r=-1;++r<_;)(l=M[r]).fixed||t.visit(n(l));for(r=-1;++r<_;)l=M[r],l.fixed?(l.x=l.px,l.y=l.py):(l.x-=(l.px-(l.px=l.x))*f,l.y-=(l.py-(l.py=l.y))*f);c.tick({type:"tick",alpha:u})},l.nodes=function(n){return arguments.length?(M=n,l):M},l.links=function(n){return arguments.length?(x=n,l):x},l.size=function(n){return arguments.length?(s=n,l):s},l.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,l):h},l.distance=l.linkDistance,l.linkStrength=function(n){return arguments.length?(g="function"==typeof n?n:+n,l):g},l.friction=function(n){return arguments.length?(f=+n,l):f},l.charge=function(n){return arguments.length?(p="function"==typeof n?n:+n,l):p},l.chargeDistance=function(n){return arguments.length?(v=n*n,l):Math.sqrt(v)},l.gravity=function(n){return arguments.length?(d=+n,l):d},l.theta=function(n){return arguments.length?(m=n*n,l):Math.sqrt(m)},l.alpha=function(n){return arguments.length?(n=+n,u?n>0?u=n:(e.c=null,e.t=NaN,e=null,c.end({type:"end",alpha:u=0})):n>0&&(c.start({type:"start",alpha:u=n}),e=qn(l.tick)),l):u},l.start=function(){function n(n,r){if(!e){for(e=new Array(u),l=0;u>l;++l)e[l]=[];for(l=0;c>l;++l){var i=x[l];e[i.source.index].push(i.target),e[i.target.index].push(i.source)}}for(var a,o=e[t],l=-1,s=o.length;++lt;++t)(r=M[t]).index=t,r.weight=0;for(t=0;c>t;++t)r=x[t],"number"==typeof r.source&&(r.source=M[r.source]),"number"==typeof r.target&&(r.target=M[r.target]),++r.source.weight,++r.target.weight;for(t=0;u>t;++t)r=M[t],isNaN(r.x)&&(r.x=n("x",f)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(i=[],"function"==typeof h)for(t=0;c>t;++t)i[t]=+h.call(this,x[t],t);else for(t=0;c>t;++t)i[t]=h;if(a=[],"function"==typeof g)for(t=0;c>t;++t)a[t]=+g.call(this,x[t],t);else for(t=0;c>t;++t)a[t]=g;if(o=[],"function"==typeof p)for(t=0;u>t;++t)o[t]=+p.call(this,M[t],t);else for(t=0;u>t;++t)o[t]=p;return l.resume()},l.resume=function(){return l.alpha(.1)},l.stop=function(){return l.alpha(0)},l.drag=function(){return r||(r=oa.behavior.drag().origin(y).on("dragstart.force",Qr).on("drag.force",t).on("dragend.force",nu)),arguments.length?void this.on("mouseover.force",tu).on("mouseout.force",eu).call(r):r},oa.rebind(l,c,"on")};var ml=20,yl=1,Ml=1/0;oa.layout.hierarchy=function(){function n(u){var i,a=[u],o=[];for(u.depth=0;null!=(i=a.pop());)if(o.push(i),(c=e.call(n,i,i.depth))&&(l=c.length)){for(var l,c,s;--l>=0;)a.push(s=c[l]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=c}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return au(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),o}var t=cu,e=ou,r=lu;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(iu(t,function(n){n.children&&(n.value=0)}),au(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},oa.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(a=i.length)){var a,o,l,c=-1;for(r=t.value?r/t.value:0;++cf?-1:1),p=oa.sum(c),v=p?(f-l*g)/p:0,d=oa.range(l),m=[];return null!=e&&d.sort(e===xl?function(n,t){return c[t]-c[n]}:function(n,t){return e(a[n],a[t])}),d.forEach(function(n){m[n]={data:a[n],value:o=c[n],startAngle:s,endAngle:s+=o*v+g,padAngle:h}}),m}var t=Number,e=xl,r=0,u=Ua,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var xl={};oa.layout.stack=function(){function n(o,l){if(!(h=o.length))return o;var c=o.map(function(e,r){return t.call(n,e,r)}),s=c.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),a.call(n,t,e)]})}),f=e.call(n,s,l);c=oa.permute(c,f),s=oa.permute(s,f);var h,g,p,v,d=r.call(n,s,l),m=c[0].length;for(p=0;m>p;++p)for(u.call(n,c[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,c[g][p],v+=s[g-1][p][1],s[g][p][1]);return o}var t=y,e=pu,r=vu,u=gu,i=fu,a=hu;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:bl.get(t)||pu,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:_l.get(t)||vu,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(a=t,n):a},n.out=function(t){return arguments.length?(u=t,n):u},n};var bl=oa.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(du),i=n.map(mu),a=oa.range(r).sort(function(n,t){return u[n]-u[t]}),o=0,l=0,c=[],s=[];for(t=0;r>t;++t)e=a[t],l>o?(o+=i[e],c.push(e)):(l+=i[e],s.push(e));return s.reverse().concat(c)},reverse:function(n){return oa.range(n.length).reverse()},"default":pu}),_l=oa.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,a=[],o=0,l=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>o&&(o=r),a.push(r)}for(e=0;i>e;++e)l[e]=(o-a[e])/2;return l},wiggle:function(n){var t,e,r,u,i,a,o,l,c,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=l=c=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,o=f[e][0]-f[e-1][0];s>t;++t){for(r=0,a=(n[t][e][1]-n[t][e-1][1])/(2*o);t>r;++r)a+=(n[r][e][1]-n[r][e-1][1])/o;i+=a*n[t][e][1]}g[e]=l-=u?i/u*o:0,c>l&&(c=l)}for(e=0;h>e;++e)g[e]-=c;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,a=1/u,o=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=a}for(e=0;i>e;++e)o[e]=0;return o},zero:vu});oa.layout.histogram=function(){function n(n,i){for(var a,o,l=[],c=n.map(e,this),s=r.call(this,c,i),f=u.call(this,s,c,i),i=-1,h=c.length,g=f.length-1,p=t?1:1/h;++i0)for(i=-1;++i=s[0]&&o<=s[1]&&(a=l[oa.bisect(f,o,1,g)-1],a.y+=p,a.push(n[i]));return l}var t=!0,e=Number,r=bu,u=Mu;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=En(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return xu(n,t)}:En(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},oa.layout.pack=function(){function n(n,i){var a=e.call(this,n,i),o=a[0],l=u[0],c=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(o.x=o.y=0,au(o,function(n){n.r=+s(n.value)}),au(o,Nu),r){var f=r*(t?1:Math.max(2*o.r/l,2*o.r/c))/2;au(o,function(n){n.r+=f}),au(o,Nu),au(o,function(n){n.r-=f})}return Cu(o,l/2,c/2,t?1:1/Math.max(2*o.r/l,2*o.r/c)),a}var t,e=oa.layout.hierarchy().sort(_u),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},uu(n,e)},oa.layout.tree=function(){function n(n,u){var s=a.call(this,n,u),f=s[0],h=t(f);if(au(h,e),h.parent.m=-h.z,iu(h,r),c)iu(f,i);else{var g=f,p=f,v=f;iu(f,function(n){n.xp.x&&(p=n),n.depth>v.depth&&(v=n)});var d=o(g,p)/2-g.x,m=l[0]/(p.x+o(p,g)/2+d),y=l[1]/(v.depth||1);iu(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,a=0,o=i.length;o>a;++a)r.push((i[a]=u={_:i[a],parent:t,children:(u=i[a].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:a}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Du(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+o(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+o(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,a=t,l=u.parent.children[0],c=u.m,s=i.m,f=a.m,h=l.m;a=Tu(a),u=qu(u),a&&u;)l=qu(l),i=Tu(i),i.a=n,r=a.z+f-u.z-c+o(a._,u._),r>0&&(Ru(Pu(a,n,e),n,r),c+=r,s+=r),f+=a.m,c+=u.m,h+=l.m,s+=i.m;a&&!Tu(i)&&(i.t=a,i.m+=f-s),u&&!qu(l)&&(l.t=u,l.m+=c-h,e=n)}return e}function i(n){n.x*=l[0],n.y=n.depth*l[1]}var a=oa.layout.hierarchy().sort(null).value(null),o=Lu,l=[1,1],c=null;return n.separation=function(t){return arguments.length?(o=t,n):o},n.size=function(t){return arguments.length?(c=null==(l=t)?i:null,n):c?null:l},n.nodeSize=function(t){return arguments.length?(c=null==(l=t)?null:i,n):c?l:null},uu(n,a)},oa.layout.cluster=function(){function n(n,i){var a,o=t.call(this,n,i),l=o[0],c=0;au(l,function(n){var t=n.children;t&&t.length?(n.x=Uu(t),n.y=ju(t)):(n.x=a?c+=e(n,a):0,n.y=0,a=n)});var s=Fu(l),f=Hu(l),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return au(l,u?function(n){n.x=(n.x-l.x)*r[0],n.y=(l.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(l.y?n.y/l.y:1))*r[1]}),o}var t=oa.layout.hierarchy().sort(null).value(null),e=Lu,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},uu(n,t)},oa.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++ut?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var a,o,l,c=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?c.dx:"dice"===g?c.dy:"slice-dice"===g?1&e.depth?c.dy:c.dx:Math.min(c.dx,c.dy);for(n(h,c.dx*c.dy/e.value),s.area=0;(l=h.length)>0;)s.push(a=h[l-1]),s.area+=a.area,"squarify"!==g||(o=r(s,v))<=p?(h.pop(),p=o):(s.area-=s.pop().area,u(s,v,c,!1),v=Math.min(c.dx,c.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,c,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,a=f(t),o=r.slice(),l=[];for(n(o,a.dx*a.dy/t.value),l.area=0;i=o.pop();)l.push(i),l.area+=i.area,null!=i.z&&(u(l,i.z?a.dx:a.dy,a,!o.length),l.length=l.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,a=-1,o=n.length;++ae&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,a=n.length,o=e.x,c=e.y,s=t?l(n.area/t):0; +if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++ie.dx)&&(s=e.dx);++ie&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=oa.random.normal.apply(oa,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=oa.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},oa.scale={};var wl={floor:y,ceil:y};oa.scale.linear=function(){return Wu([0,1],[0,1],Mr,!1)};var Sl={s:1,g:1,p:1,r:1,e:1};oa.scale.log=function(){return ri(oa.scale.linear().domain([0,1]),10,!0,[1,10])};var kl=oa.format(".0e"),Nl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};oa.scale.pow=function(){return ui(oa.scale.linear(),1,[0,1])},oa.scale.sqrt=function(){return oa.scale.pow().exponent(.5)},oa.scale.ordinal=function(){return ai([],{t:"range",a:[[]]})},oa.scale.category10=function(){return oa.scale.ordinal().range(El)},oa.scale.category20=function(){return oa.scale.ordinal().range(Al)},oa.scale.category20b=function(){return oa.scale.ordinal().range(Cl)},oa.scale.category20c=function(){return oa.scale.ordinal().range(zl)};var El=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Al=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),Cl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),zl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);oa.scale.quantile=function(){return oi([],[])},oa.scale.quantize=function(){return li(0,1,[0,1])},oa.scale.threshold=function(){return ci([.5],[0,1])},oa.scale.identity=function(){return si([0,1])},oa.svg={},oa.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),c=Math.max(0,+r.apply(this,arguments)),s=a.apply(this,arguments)-Ha,f=o.apply(this,arguments)-Ha,h=Math.abs(f-s),g=s>f?0:1;if(n>c&&(p=c,c=n,n=p),h>=Fa)return t(c,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,N=0,E=0,A=[];if((m=(+l.apply(this,arguments)||0)/2)&&(d=i===Ll?Math.sqrt(n*n+c*c):+i.apply(this,arguments),g||(E*=-1),c&&(E=tn(d/c*Math.sin(m))),n&&(N=tn(d/n*Math.sin(m)))),c){y=c*Math.cos(s+E),M=c*Math.sin(s+E),x=c*Math.cos(f-E),b=c*Math.sin(f-E);var C=Math.abs(f-s-2*E)<=ja?0:1;if(E&&mi(y,M,x,b)===g^C){var z=(s+f)/2;y=c*Math.cos(z),M=c*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-N),w=n*Math.sin(f-N),S=n*Math.cos(s+N),k=n*Math.sin(s+N);var L=Math.abs(s-f+2*N)<=ja?0:1;if(N&&mi(_,w,S,k)===1-g^L){var q=(s+f)/2;_=n*Math.cos(q),w=n*Math.sin(q),S=k=null}}else _=w=0;if(h>Da&&(p=Math.min(Math.abs(c-n)/2,+u.apply(this,arguments)))>.001){v=c>n^g?0:1;var T=p,R=p;if(ja>h){var D=null==S?[_,w]:null==x?[y,M]:Re([y,M],[S,k],[x,b],[_,w]),P=y-D[0],j=M-D[1],U=x-D[0],F=b-D[1],H=1/Math.sin(Math.acos((P*U+j*F)/(Math.sqrt(P*P+j*j)*Math.sqrt(U*U+F*F)))/2),O=Math.sqrt(D[0]*D[0]+D[1]*D[1]);R=Math.min(p,(n-O)/(H-1)),T=Math.min(p,(c-O)/(H+1))}if(null!=x){var I=yi(null==S?[_,w]:[S,k],[y,M],c,T,g),Y=yi([x,b],[_,w],c,T,g);p===T?A.push("M",I[0],"A",T,",",T," 0 0,",v," ",I[1],"A",c,",",c," 0 ",1-g^mi(I[1][0],I[1][1],Y[1][0],Y[1][1]),",",g," ",Y[1],"A",T,",",T," 0 0,",v," ",Y[0]):A.push("M",I[0],"A",T,",",T," 0 1,",v," ",Y[0])}else A.push("M",y,",",M);if(null!=S){var Z=yi([y,M],[S,k],n,-R,g),V=yi([_,w],null==x?[y,M]:[x,b],n,-R,g);p===R?A.push("L",V[0],"A",R,",",R," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^mi(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",R,",",R," 0 0,",v," ",Z[0]):A.push("L",V[0],"A",R,",",R," 0 0,",v," ",Z[0])}else A.push("L",_,",",w)}else A.push("M",y,",",M),null!=x&&A.push("A",c,",",c," 0 ",C,",",g," ",x,",",b),A.push("L",_,",",w),null!=S&&A.push("A",n,",",n," 0 ",L,",",1-g," ",S,",",k);return A.push("Z"),A.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=hi,r=gi,u=fi,i=Ll,a=pi,o=vi,l=di;return n.innerRadius=function(t){return arguments.length?(e=En(t),n):e},n.outerRadius=function(t){return arguments.length?(r=En(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=En(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==Ll?Ll:En(t),n):i},n.startAngle=function(t){return arguments.length?(a=En(t),n):a},n.endAngle=function(t){return arguments.length?(o=En(t),n):o},n.padAngle=function(t){return arguments.length?(l=En(t),n):l},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+a.apply(this,arguments)+ +o.apply(this,arguments))/2-Ha;return[Math.cos(t)*n,Math.sin(t)*n]},n};var Ll="auto";oa.svg.line=function(){return Mi(y)};var ql=oa.map({linear:xi,"linear-closed":bi,step:_i,"step-before":wi,"step-after":Si,basis:zi,"basis-open":Li,"basis-closed":qi,bundle:Ti,cardinal:Ei,"cardinal-open":ki,"cardinal-closed":Ni,monotone:Fi});ql.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Tl=[0,2/3,1/3,0],Rl=[0,1/3,2/3,0],Dl=[0,1/6,2/3,1/6];oa.svg.line.radial=function(){var n=Mi(Hi);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wi.reverse=Si,Si.reverse=wi,oa.svg.area=function(){return Oi(y)},oa.svg.area.radial=function(){var n=Oi(Hi);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},oa.svg.chord=function(){function n(n,o){var l=t(this,i,n,o),c=t(this,a,n,o);return"M"+l.p0+r(l.r,l.p1,l.a1-l.a0)+(e(l,c)?u(l.r,l.p1,l.r,l.p0):u(l.r,l.p1,c.r,c.p0)+r(c.r,c.p1,c.a1-c.a0)+u(c.r,c.p1,l.r,l.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=o.call(n,u,r),a=l.call(n,u,r)-Ha,s=c.call(n,u,r)-Ha;return{r:i,a0:a,a1:s,p0:[i*Math.cos(a),i*Math.sin(a)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>ja)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=Me,a=xe,o=Ii,l=pi,c=vi;return n.radius=function(t){return arguments.length?(o=En(t),n):o},n.source=function(t){return arguments.length?(i=En(t),n):i},n.target=function(t){return arguments.length?(a=En(t),n):a},n.startAngle=function(t){return arguments.length?(l=En(t),n):l},n.endAngle=function(t){return arguments.length?(c=En(t),n):c},n},oa.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),a=e.call(this,n,u),o=(i.y+a.y)/2,l=[i,{x:i.x,y:o},{x:a.x,y:o},a];return l=l.map(r),"M"+l[0]+"C"+l[1]+" "+l[2]+" "+l[3]}var t=Me,e=xe,r=Yi;return n.source=function(e){return arguments.length?(t=En(e),n):t},n.target=function(t){return arguments.length?(e=En(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},oa.svg.diagonal.radial=function(){var n=oa.svg.diagonal(),t=Yi,e=n.projection;return n.projection=function(n){return arguments.length?e(Zi(t=n)):t},n},oa.svg.symbol=function(){function n(n,r){return(Pl.get(t.call(this,n,r))||$i)(e.call(this,n,r))}var t=Xi,e=Vi;return n.type=function(e){return arguments.length?(t=En(e),n):t},n.size=function(t){return arguments.length?(e=En(t),n):e},n};var Pl=oa.map({circle:$i,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ul)),e=t*Ul;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});oa.svg.symbolTypes=Pl.keys();var jl=Math.sqrt(3),Ul=Math.tan(30*Oa);Aa.transition=function(n){for(var t,e,r=Fl||++Yl,u=Ki(n),i=[],a=Hl||{time:Date.now(),ease:Nr,delay:0,duration:250},o=-1,l=this.length;++oi;i++){u.push(t=[]);for(var e=this[i],o=0,l=e.length;l>o;o++)(r=e[o])&&n.call(r,r.__data__,o,i)&&t.push(r)}return Wi(u,this.namespace,this.id)},Il.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Il.attr=function(n,t){function e(){this.removeAttribute(o)}function r(){this.removeAttributeNS(o.space,o.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(o);return e!==n&&(t=a(e,n),function(n){this.setAttribute(o,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(o.space,o.local);return e!==n&&(t=a(e,n),function(n){this.setAttributeNS(o.space,o.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var a="transform"==n?$r:Mr,o=oa.ns.qualify(n);return Ji(this,"attr."+n,t,o.local?i:u)},Il.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=oa.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Il.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=Mr(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var a=arguments.length;if(3>a){if("string"!=typeof n){2>a&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Ji(this,"style."+n,e,i)},Il.styleTween=function(n,e,r){function u(u,i){var a=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return a&&function(t){this.style.setProperty(n,a(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Il.text=function(n){return Ji(this,"text",n,Gi)},Il.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Il.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=oa.ease.apply(oa,arguments)),Y(this,function(r){r[e][t].ease=n}))},Il.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Il.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Il.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Hl,i=Fl;try{Fl=e,Y(this,function(t,u,i){Hl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Hl=u,Fl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=oa.dispatch("start","end","interrupt"))).on(n,t)});return this},Il.transition=function(){for(var n,t,e,r,u=this.id,i=++Yl,a=this.namespace,o=[],l=0,c=this.length;c>l;l++){o.push(n=[]);for(var t=this[l],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[a][u],Qi(e,s,a,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Wi(o,a,i)},oa.svg.axis=function(){function n(n){n.each(function(){var n,c=oa.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==l?f.ticks?f.ticks.apply(f,o):f.domain():l,g=null==t?f.tickFormat?f.tickFormat.apply(f,o):y:t,p=c.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Da),d=oa.transition(p.exit()).style("opacity",Da).remove(),m=oa.transition(p.order()).style("opacity",1),M=Math.max(u,0)+a,x=Zu(f),b=c.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),oa.transition(b));v.append("line"),v.append("text");var w,S,k,N,E=v.select("line"),A=m.select("line"),C=p.select("text").text(g),z=v.select("text"),L=m.select("text"),q="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=na,w="x",k="y",S="x2",N="y2",C.attr("dy",0>q?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+q*i+"V0H"+x[1]+"V"+q*i)):(n=ta,w="y",k="x",S="y2",N="x2",C.attr("dy",".32em").style("text-anchor",0>q?"end":"start"),_.attr("d","M"+q*i+","+x[0]+"H0V"+x[1]+"H"+q*i)),E.attr(N,q*u),z.attr(k,q*M),A.attr(S,0).attr(N,q*u),L.attr(w,0).attr(k,q*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=oa.scale.linear(),r=Zl,u=6,i=6,a=3,o=[10],l=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Vl?t+"":Zl,n):r},n.ticks=function(){return arguments.length?(o=ca(arguments),n):o},n.tickValues=function(t){return arguments.length?(l=t,n):l},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(a=+t,n):a},n.tickSubdivide=function(){return arguments.length&&n},n};var Zl="bottom",Vl={top:1,right:1,bottom:1,left:1};oa.svg.brush=function(){function n(t){t.each(function(){var t=oa.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),a=t.selectAll(".background").data([0]);a.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var o=t.selectAll(".resize").data(v,y);o.exit().remove(),o.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Xl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),o.style("display",n.empty()?"none":null);var l,f=oa.transition(t),h=oa.transition(a);c&&(l=Zu(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),r(f)),s&&(l=Zu(s),h.attr("y",l[0]).attr("height",l[1]-l[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==oa.event.keyCode&&(C||(M=null,L[0]-=f[1],L[1]-=h[1],C=2),S())}function v(){32==oa.event.keyCode&&2==C&&(L[0]+=f[1],L[1]+=h[1],C=0,S())}function d(){var n=oa.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(oa.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),L[0]=f[+(n[0]s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?o=null:a=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),oa.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=oa.select(oa.event.target),w=l.of(b,arguments),k=oa.select(b),N=_.datum(),E=!/^(n|s)$/.test(N)&&c,A=!/^(e|w)$/.test(N)&&s,C=_.classed("extent"),z=W(b),L=oa.mouse(b),q=oa.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(oa.event.changedTouches?q.on("touchmove.brush",d).on("touchend.brush",y):q.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)L[0]=f[0]-L[0],L[1]=h[0]-L[1];else if(N){var T=+/w$/.test(N),R=+/^n/.test(N);x=[f[1-T]-L[0],h[1-R]-L[1]],L[0]=f[T],L[1]=h[R]}else oa.event.altKey&&(M=L.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),oa.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var a,o,l=N(n,"brushstart","brush","brushend"),c=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=$l[0];return n.event=function(n){n.each(function(){var n=l.of(this,arguments),t={x:f,y:h,i:a,j:o},e=this.__chart__||t;this.__chart__=t,Fl?oa.select(this).transition().each("start.brush",function(){a=e.i,o=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(f,t.x),r=xr(h,t.y);return a=o=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){a=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,v=$l[!c<<1|!s],n):c},n.y=function(t){return arguments.length?(s=t,v=$l[!c<<1|!s],n):s},n.clamp=function(t){return arguments.length?(c&&s?(g=!!t[0],p=!!t[1]):c?g=!!t:s&&(p=!!t),n):c&&s?[g,p]:c?g:s?p:null},n.extent=function(t){var e,r,u,i,l;return arguments.length?(c&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),a=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(l=e,e=r,r=l),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],c&&(u=u[1],i=i[1]),o=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(l=u,u=i,i=l),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(c&&(a?(e=a[0],r=a[1]):(e=f[0],r=f[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(l=e,e=r,r=l))),s&&(o?(u=o[0],i=o[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(l=u,u=i,i=l))),c&&s?[[e,u],[r,i]]:c?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],a=o=null),n},n.empty=function(){return!!c&&f[0]==f[1]||!!s&&h[0]==h[1]},oa.rebind(n,l,"on")};var Xl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},$l=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Bl=ho.format=Mo.timeFormat,Wl=Bl.utc,Jl=Wl("%Y-%m-%dT%H:%M:%S.%LZ");Bl.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ea:Jl,ea.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},ea.toString=Jl.toString,ho.second=On(function(n){return new go(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ho.seconds=ho.second.range,ho.seconds.utc=ho.second.utc.range,ho.minute=On(function(n){return new go(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ho.minutes=ho.minute.range,ho.minutes.utc=ho.minute.utc.range,ho.hour=On(function(n){var t=n.getTimezoneOffset()/60;return new go(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ho.hours=ho.hour.range,ho.hours.utc=ho.hour.utc.range,ho.month=On(function(n){return n=ho.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ho.months=ho.month.range,ho.months.utc=ho.month.utc.range;var Gl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Kl=[[ho.second,1],[ho.second,5],[ho.second,15],[ho.second,30],[ho.minute,1],[ho.minute,5],[ho.minute,15],[ho.minute,30],[ho.hour,1],[ho.hour,3],[ho.hour,6],[ho.hour,12],[ho.day,1],[ho.day,2],[ho.week,1],[ho.month,1],[ho.month,3],[ho.year,1]],Ql=Bl.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",zt]]),nc={range:function(n,t,e){return oa.range(Math.ceil(n/e)*e,+t,e).map(ua)},floor:y,ceil:y};Kl.year=ho.year,ho.scale=function(){return ra(oa.scale.linear(),Kl,Ql)};var tc=Kl.map(function(n){return[n[0].utc,n[1]]}),ec=Wl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",zt]]);tc.year=ho.year.utc,ho.scale.utc=function(){return ra(oa.scale.linear(),tc,ec)},oa.text=An(function(n){return n.responseText}),oa.json=function(n,t){return Cn(n,"application/json",ia,t)},oa.html=function(n,t){return Cn(n,"text/html",aa,t)},oa.xml=An(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=oa,define(oa)):"object"==typeof module&&module.exports?module.exports=oa:this.d3=oa}(); \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/download.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/download.js new file mode 100644 index 000000000..11ed5778c --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/download.js @@ -0,0 +1,174 @@ +/* + * 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. + */ + +var modalPopup = ".wr-modalpopup"; +var modalPopupContainer = modalPopup + " .modalpopup-container"; +var modalPopupContent = modalPopup + " .modalpopup-content"; +var body = "body"; + +/* + * set popup maximum height function. + */ +function setPopupMaxHeight() { + $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30))); + $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2))); +} + +/* + * show popup function. + */ +function showPopup() { + $(modalPopup).show(); + setPopupMaxHeight(); + $('#downloadForm').validate({ + rules: { + deviceName: { + minlength: 4, + required: true + } + }, + highlight: function (element) { + $(element).closest('.control-group').removeClass('success').addClass('error'); + }, + success: function (element) { + $(element).closest('.control-group').removeClass('error').addClass('success'); + $('label[for=deviceName]').remove(); + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); +} + +/* + * hide popup function. + */ +function hidePopup() { + $('label[for=deviceName]').remove(); + $('.control-group').removeClass('success').removeClass('error'); + $(modalPopupContent).html(''); + $(modalPopup).hide(); +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + attachEvents(); +}); + +function attachEvents() { + /** + * Following click function would execute + * when a user clicks on "Download" link + * on Device Management page in WSO2 DC Console. + */ + $("a.download-link").click(function () { + var sketchType = $(this).data("sketchtype"); + var deviceType = $(this).data("devicetype"); + var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link"; + var payload = {"sketchType": sketchType, "deviceType": deviceType}; + $(modalPopupContent).html($('#download-device-modal-content').html()); + showPopup(); + var deviceName; + $("a#download-device-download-link").click(function () { + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + $('label[for=deviceName]').remove(); + if (deviceName && deviceName.length >= 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() { + $('#downloadForm').submit(); + + var deviceName; + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + if (deviceName && deviceName.length >= 4) { + setTimeout(function () { + hidePopup(); + }, 1000); + } +} + +function doAction(data) { + //if it is saml redirection response + if (data.status == null) { + document.write(data); + } + + if (data.status == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showPopup(); + } else 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/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/initJs b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/initJs new file mode 100644 index 000000000..57f70e56a --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/initJs @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015, 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. + */ +var ajax_handler = new ajax_handler(); +var config_api = new config_api(); +var plotting = new plotting(); +var object_maker = new object_maker(); \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jQueryRotate.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jQueryRotate.js new file mode 100644 index 000000000..e3a8fa9c3 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jQueryRotate.js @@ -0,0 +1,357 @@ +/* + * 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. + */ + +// VERSION: 2.3 LAST UPDATE: 11.07.2013 +/* + * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php + * + * Made by Wilq32, wilq32@gmail.com, Wroclaw, Poland, 01.2009 + * Website: http://jqueryrotate.com + */ + +(function($) { + var supportedCSS,supportedCSSOrigin, styles=document.getElementsByTagName("head")[0].style,toCheck="transformProperty WebkitTransform OTransform msTransform MozTransform".split(" "); + for (var a = 0; a < toCheck.length; a++) if (styles[toCheck[a]] !== undefined) { supportedCSS = toCheck[a]; } + if (supportedCSS) { + supportedCSSOrigin = supportedCSS.replace(/[tT]ransform/,"TransformOrigin"); + if (supportedCSSOrigin[0] == "T") supportedCSSOrigin[0] = "t"; + } + + // Bad eval to preven google closure to remove it from code o_O + eval('IE = "v"=="\v"'); + + jQuery.fn.extend({ + rotate:function(parameters) + { + if (this.length===0||typeof parameters=="undefined") return; + if (typeof parameters=="number") parameters={angle:parameters}; + var returned=[]; + for (var i=0,i0=this.length;i this._parameters.duration; + + // TODO: Bug for animatedGif for static rotation ? (to test) + if (checkEnd && !this._parameters.animatedGif) + { + clearTimeout(this._timer); + } + else + { + if (this._canvas||this._vimage||this._img) { + var angle = this._parameters.easing(0, actualTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration); + this._rotate((~~(angle*10))/10); + } + if (this._parameters.step) { + this._parameters.step(this._angle); + } + var self = this; + this._timer = setTimeout(function() + { + self._animate.call(self); + }, 10); + } + + // To fix Bug that prevents using recursive function in callback I moved this function to back + if (this._parameters.callback && checkEnd){ + this._angle = this._parameters.animateTo; + this._rotate(this._angle); + this._parameters.callback.call(this._rootObj); + } + }, + + _rotate : (function() + { + var rad = Math.PI/180; + if (IE) + return function(angle) + { + this._angle = angle; + this._container.style.rotation=(angle%360)+"deg"; + this._vimage.style.top = -(this._rotationCenterY - this._imgHeight/2) + "px"; + this._vimage.style.left = -(this._rotationCenterX - this._imgWidth/2) + "px"; + this._container.style.top = this._rotationCenterY - this._imgHeight/2 + "px"; + this._container.style.left = this._rotationCenterX - this._imgWidth/2 + "px"; + + } + else if (supportedCSS) + return function(angle){ + this._angle = angle; + this._img.style[supportedCSS]="rotate("+(angle%360)+"deg)"; + this._img.style[supportedCSSOrigin]=this._parameters.center.join(" "); + } + else + return function(angle) + { + this._angle = angle; + angle=(angle%360)* rad; + // clear canvas + this._canvas.width = this._width;//+this._widthAdd; + this._canvas.height = this._height;//+this._heightAdd; + + // REMEMBER: all drawings are read from backwards.. so first function is translate, then rotate, then translate, translate.. + this._cnv.translate(this._imgWidth*this._aspectW,this._imgHeight*this._aspectH); // at least center image on screen + this._cnv.translate(this._rotationCenterX,this._rotationCenterY); // we move image back to its orginal + this._cnv.rotate(angle); // rotate image + this._cnv.translate(-this._rotationCenterX,-this._rotationCenterY); // move image to its center, so we can rotate around its center + this._cnv.scale(this._aspectW,this._aspectH); // SCALE - if needed ;) + this._cnv.drawImage(this._img, 0, 0); // First - we draw image + } + + })() + } + + if (IE) + { + Wilq32.PhotoEffect.prototype.createVMLNode=(function(){ + document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); + try { + !document.namespaces.rvml && document.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); + return function (tagName) { + return document.createElement(''); + }; + } catch (e) { + return function (tagName) { + return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); + }; + } + })(); + } + +})(jQuery); diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jquery.validate.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/mainHandler b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/mainHandler new file mode 100644 index 000000000..28199109a --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/mainHandler @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, 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. + */ + +object_maker.init(config_api.config_3dobject_holder, $("#objectHolder").width(), $("#objectHolder").width()/1.5); +object_maker.animate(); +var flight_dynamics = new flight_dynamics(); +$("#window_size").slider({ + range: "min", + value: 37, + min: 10, + max: 300, + slide: function (event, ui) { + $("#window_size_current_value").html($("#window_size").slider("value")); + + } +}); +$("#window_update").slider({ + range: "min", + value: 234, + min: 100, + max: 1000, + slide: function (event, ui) { + $("#window_update_value").html($("#window_update").slider("value")); + } +}); +$("#replotting").click(function () { + plotting.finishPlotting(function (status) { + if (status) { + plotting.initPlotting(function (status) { + d3.select("#realtimechart").select("svg").remove(); + plotting.realtime_plotting("#realtimechart", "#range_min", "#range_max", "#window_update_value", + 600, $("#realtimechart").height(), "#window_size_current_value", + '#plotting_attribute'); + }); + } else { + $("#realtimechart").html("There is no data to plot"); + } + }); +}); +$('.btn-minimize').click(function (e) { + e.preventDefault(); + var $target = $(this).parent().parent().next('.box-content'); + if ($target.is(':visible')) { + if ($(this).parent().attr('id') === "RealtimePlotting") { + plotting.forceToRedraw(function (status) { + d3.select("#realtimechart").select("svg").remove(); + plotting.realtime_plotting("#realtimechart", "#range_min", "#range_max", "#window_update_value", + 600, $("#realtimechart").height(), "#window_size_current_value", + '#plotting_attribute'); + }); + } + } else { + } +}); +$('#connectionOpen').on('click', function () { + $('#connectionOpen').toggleClass('active'); +}); +$("#xmppConnectionOpen").on('click', function () { + $('#xmppConnectionOpen').toggleClass('active'); + if ($('#xmppConnectionOpen').html() === "Start") { + sendMessage("Start the process", function(state){ + console.log("sending message to server..."+ state); + if(state<2){ + $('#xmppConnectionOpen').html("Stop"); + }else{ + $('#xmppConnectionOpen').html("Start"); + } + }); + + } else if ($('#xmppConnectionOpen').html() === "Stop") { + closeSocket(function(state){ + console.log("closing WebSocket..."+ state); + if(state<2){ + $('#xmppConnectionOpen').html("Stop"); + }else{ + $('#xmppConnectionOpen').html("Start"); + } + }); + $("#connectionOpen").html("Connect to XMPP Server").removeClass("btn btn-info").addClass("btn btn-primary"); + } +}); + +$('.btn-minimize').parent().parent().next('.box-content').hide(); +var webSocket; +config_api.realtime_plotting_data_window["attitude"] = new Queue(); +var current_status = {}; +function openSocket(wssAddress) { + if (webSocket !== undefined && webSocket.readyState == 1) { + writeResponse("WebSocket is already opened."); + } else { + webSocket = new WebSocket(wssAddress+config_api.web_socket_endpoint); + } + webSocket.onopen = function (event) { + if (event === undefined) { + writeResponse("WebSocket cant open " + event); + $("#connectionOpen").html("Connect to server").removeClass("btn btn-info").addClass("btn btn-primary"); + } else { + + if (event["isTrusted"] == true) { + $("#connectionOpen").html("Connected").removeClass("btn btn-primary").addClass("btn btn-info"); + } + writeResponse(JSON.stringify(event)); + + } + }; + webSocket.onmessage = function (event) { + var sender_message = event.data; + sender_message = isJSON(sender_message); + if (sender_message != null) { + flight_dynamics.processingMessage(sender_message); + } else { + writeResponse("Message has been corrupted."); + } + }; +} + +function sendMessage(message, callback) { + if(webSocket.readyState<2){ + webSocket.send(message); + } + callback(webSocket.readyState); +} + +function closeSocket(callback) { + if(webSocket.readyState<2){ + webSocket.close(); + } + callback(webSocket.readyState); +} + +function writeResponse(text) { + console.log(text); +} + +window.onbeforeunload = function () { + webSocket.close(); +}; + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/controller.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/controller.js new file mode 100644 index 000000000..5381923a2 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/controller.js @@ -0,0 +1,29 @@ +/* + * 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. + */ +$("#module_control button").click(function (index) { + console.log("Asking Server to send the " + $(this).attr('id') + " command to Ar Drone"); + var url = config_api.drone_control; + ajax_handler.ajaxRequest(url, config_api.drone_controlType, {action: $(this).attr('id'), speed: 7, duration: 7}, + config_api.drone_controlDataType, function (data, status) { + console.log(JSON.stringify(data)); + } + ); +}); + + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/flight_dynamics.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/flight_dynamics.js new file mode 100644 index 000000000..64814b6ab --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/flight_dynamics.js @@ -0,0 +1,77 @@ +/* + * 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. + */ + +var flight_dynamics = function () { + var api = this; + api.processingMessage = function (sender_message) { + if(sender_message.battery_level!= undefined){ + $("#battery_level_holder").width( parseInt(sender_message.battery_level)+"%" ); + $("#battery_level").html(sender_message.battery_level+"%"); + } + if (sender_message.quatanium_val != undefined) { + current_status = object_maker.get_heading_attitude_bank(sender_message.quatanium_val); + object_maker.set_heading_attitude_bank(current_status); + $("#imageTop").animate({rotate: '' + (180 / Math.PI) * 2.890456 + 'deg'}, 2); + } + if (config_api.modules_status.angleOfRotation_2 || config_api.modules_status.angleOfRotation_1) { + console.log(JSON.stringify(current_status)); + object_maker.set_bank("#imageTop", current_status.bank); + object_maker.set_heading("#imageBackSecond", current_status.heading); + + } + if (config_api.modules_status.realtimePlotting) { + if (current_status[$('#plotting_attribute').val()] != undefined) { + plotting.pushData(current_status[$('#plotting_attribute').val()]); + } + } + if (sender_message.basicParam != undefined) { + if (sender_message.basicParam.velocity != undefined) { + var velocity = sender_message.basicParam.velocity; + if (velocity.length == 3) { + $("#velocityx").html(velocity[0]); + $("#velocityy").html(velocity[1]); + $("#velocityz").html(velocity[2]); + } + } else { + $("#velocityx").html(NaN); + $("#velocityy").html(NaN); + $("#velocityz").html(NaN); + } + if (sender_message.basicParam.global_location != undefined) { + var location = sender_message.basicParam.global_location; + if (location.length == 3) { + $("#locationLog").html(location[0]); + $("#locationAlt").html(location[1]); + $("#locationLat").html(location[2]); + } + } else { + $("#locationLog").html(NaN); + $("#locationAlt").html(NaN); + $("#locationLat").html(NaN); + } + } + if (sender_message.battery_voltage != undefined) { + $("#battery_voltage").html(sender_message.battery_voltage); + } else { + $("#battery_voltage").html(NaN); + } + } + +}; + + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/realtime_plotting b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/realtime_plotting new file mode 100644 index 000000000..064ff2e10 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/public/js/modules/realtime_plotting @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, 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. + */ +var plotting = function () { + var api = this; + api.isDone = false; + api.current_value = 0; + api.finishPlotting = function (callBack) { + api.isDone = true; + callBack(true); + }, + api.initPlotting = function (callback) { + api.isDone = false; + callback(true); + }, + api.forceToRedraw = function (callback) { + api.isDone == true; + callback(true); + }, + api.pushData = function (new_value) { + console.log(new_value); + api.current_value = new_value; + }, + api.realtime_plotting = function (holder, y_min_hollder, y_max_holder, update_interval_holder, holder_width, + holder_height, window_size_holder, title) { + $(holder).html(); + var init_window = function () { + return 0; + } + api.data = d3.range(parseInt($(window_size_holder).html())).map(init_window); + var margin = {top: 20, right: 20, bottom: 20, left: 40}, + width = holder_width - margin.left - margin.right, + height = holder_height - margin.top - margin.bottom; + var x = d3.scale.linear() + .domain([1, parseInt($(window_size_holder).html()) - 2]) + .range([0, width]); + + var y = d3.scale.linear() + .domain([parseInt($(y_min_hollder).val()), parseInt($(y_max_holder).val())]) + .range([height, 0]); + var line = d3.svg.line() + .interpolate("basis") + .x(function (d, i) { + return x(i); + }) + .y(function (d, i) { + return y(d); + }); + + var svg = d3.select(holder).append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + svg.append("defs").append("clipPath") + .attr("id", "clip") + .append("rect") + .attr("width", width) + .attr("height", height); + var axis_x = svg.append("g") + .attr("class", "x_axis") + .attr("transform", "translate(0," + y(0) + ")") + .call(d3.svg.axis().scale(x).orient("bottom")); + var axis_y = svg.append("g") + .attr("class", "y_axis") + .call(d3.svg.axis().scale(y).orient("left")); + var path = svg.append("g") + .attr("clip-path", "url(#clip)") + .append("path") + .datum(api.data) + .attr("class", "line") + .attr("d", line); + svg.append("text") + .attr("class", "yaxis_label") + .attr("transform", "rotate(-90)") + .attr("y", 0 - margin.left - 4) + .attr("x", (0 - (height / 2))) + .attr("dy", "1em") + .style("text-anchor", "middle") + .text($(title).val()); + svg.append("text") + .attr("class", "xaixs_label") + .attr("transform", + "translate(" + (width / 2) + " ," + + (height + margin.bottom) + ")") + .style("text-anchor", "middle") + .text("Window Size"); + svg.append("text") + .attr("class", "title_label") + .attr("x", (width / 2)) + .attr("y", 0 - (margin.top / 4)) + .attr("text-anchor", "middle") + .style("font-size", "16px") + .style("text-decoration", "underline") + .text($(title).val() + " variation within last " + $(window_size_holder).html() + " frames"); + + updateAgain(); + + function updateAgain() { + if (api.isDone)return; + api.data.push(api.current_value); + path + .attr("d", line) + .attr("transform", null) + .transition() + .duration($(update_interval_holder).html()) + .ease("linear") + .attr("transform", "translate(" + x(0) + ",0)") + .each("end", updateAgain); + api.data.shift(); + } + + function rescale() { + y.domain([parseInt($(y_min_hollder).val()), parseInt($(y_max_holder).val())]) + + svg.select(".title_label") + .text($(title).val() + " variation within last " + $(window_size_holder).html() + " frames"); + svg.select(".yaxis_label") + .text($(title).val()); + + } + + function rescale_x() { + x.domain([1, parseInt($(window_size_holder).html()) - 2]).range([0, width]) + svg.select(".x_axis").transition().call(axis_x); + } + + $("#plotting_attribute").change(function () { + rescale(); + }); + + } +} + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.hbs b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.hbs new file mode 100644 index 000000000..2f004fd74 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.hbs @@ -0,0 +1,250 @@ +{{#zone "topCss"}} + {{css "css/main-app.css" }} +{{/zone}} +

      +
      +
      +
      + +
      +
      + +
      +
      +

      Battery Level

      +
      +
      +
      +
      +

      0%

      +
      +
      +
      +
      +
      +
      + +
      +
      +
      +
      +
      +

      Angle of Rotation

      + +
      + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      + +
      + +
      +
      +
      +
      + + + +
      +
      +
      +
      +
      +
      +
      + +
      + +
      +
      +
      +
      + + + +
      +
      +
      +
      + +
      +
      +
      +

      Live Video Stream

      + +
      + +
      +
      +
      + video stream +
      +
      +
      +
      +
      + +
      +
      +
      +
      +
      +

      Sensor Readings

      +
      + +
      +
      +
      +
      +

      Location
      latitude:
      + longitude:
      + altitudes:

      +

      Velocity:
      x :
      + y :
      + z :

      +

      Battery Voltage:

      +
      +
      +
      +
      +
      +
      +
      +

      Realtime Plotting

      + +
      + +
      +
      +
      +
      +
      +
      + Window size : +

      + Update period : +
      +

      +
      Y-axis: +
      +

      +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      +{{#zone "bottomJs"}} + {{js "/js/d3.min.js" }} + {{js "/js/3dobject_controller/three.min.js" }} + {{js "/js/3dobject_controller/Coordinates.js" }} + {{js "/js/3dobject_controller/OrbitAndPanControls.js" }} + {{js "/js/3dobject_controller/3dObjectControler.js" }} + {{js "/js/jQueryRotate.js" }} + {{js "/js/config/config.js" }} + {{js "/js/common/ajax_handler.js" }} + {{js "/js/modules/realtime_plotting" }} + {{js "/js/initJs" }} + {{js "/js/common/general_handler" }} + {{js "/js/common/websocket_api" }} + {{js "/js/modules/controller.js" }} + {{js "/js/modules/flight_dynamics.js" }} + {{js "/js/mainHandler" }} +{{/zone}} + diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.js b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.js new file mode 100644 index 000000000..550eddedc --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.js @@ -0,0 +1,25 @@ +/* + * 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("statistics.js"); + var serverAddress = require("/app/modules/serverAddress.js").serverAddress; + var wssAddress = serverAddress.getWSSAddress(); + var httpsAddress = serverAddress.getHPPSTSAddress(); + var device = context.unit.params.device; + return { "device": device, "wssAddress": wssAddress, "httpsAddress": httpsAddress}; +} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.json b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.json new file mode 100644 index 000000000..688e93980 --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/org.wso2.carbon.device.mgt.iot.droneanalyzer.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.droneanalyzer.statistics/statistics.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/drone-analyzer-plugin/pom.xml b/components/iot-plugins/drone-analyzer-plugin/pom.xml new file mode 100644 index 000000000..4260130be --- /dev/null +++ b/components/iot-plugins/drone-analyzer-plugin/pom.xml @@ -0,0 +1,61 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + drone-analyzer-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.droneanalyzer.ui + org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api + org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api + org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/pom.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/pom.xml new file mode 100644 index 000000000..b81253fe7 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/pom.xml @@ -0,0 +1,139 @@ + + + + + + iot-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.api + war + WSO2 Carbon - IoT Server API - Common APIs + WSO2 Carbon - IoT Server API for common device functionality + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.common + provided + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.datasource.commons + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + common + + + + + + + + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/log4j.properties b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/log4j.properties new file mode 100755 index 000000000..c271582fa --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/log4j.properties @@ -0,0 +1,8 @@ +# Root logger option +log4j.rootLogger=INFO, stdout + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %c{1}:%L - %m%n \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DeviceUsageDTO.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DeviceUsageDTO.java new file mode 100644 index 000000000..222f00d41 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DeviceUsageDTO.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.api; + +public class DeviceUsageDTO { + + private String time; + private String value; + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java new file mode 100644 index 000000000..58841062b --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.*; +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.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +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.jws.WebService; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +@WebService public class DevicesManagerService { + + private static Log log = LogFactory.getLog(DevicesManagerService.class); + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + + private PrivilegedCarbonContext ctx; + + private DeviceManagementProviderService getServiceProvider() { + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + PrivilegedCarbonContext.startTenantFlow(); + ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain(tenantDomain, true); + if (log.isDebugEnabled()) { + log.debug("Getting thread local carbon context for tenant domain: " + tenantDomain); + } + return (DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + } + + private void endTenantFlow() { + PrivilegedCarbonContext.endTenantFlow(); + ctx = null; + if (log.isDebugEnabled()) { + log.debug("Tenant flow ended"); + } + } + + private Device[] getActiveDevices(List devices){ + List activeDevices = new ArrayList<>(); + if (devices != null) { + for (Device device : devices) { + if (device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) { + activeDevices.add(device); + } + } + } + return activeDevices.toArray(new Device[activeDevices.size()]); + } + + @Path("/device/user/{username}/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getDevicesOfUser(@PathParam("username") String username) { + try { + List devices = this.getServiceProvider().getDevicesOfUser(username); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/user/{username}/ungrouped") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getUnGroupedDevices(@PathParam("username") String username){ + try{ + List devices = this.getServiceProvider().getUnGroupedDevices(username); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/user/{username}/all/count") + @GET + @Consumes("application/json") + @Produces("application/json") + public int getDeviceCount(@PathParam("username") String username){ + try { + List devices = this.getServiceProvider().getDevicesOfUser(username); + if (devices != null) { + List activeDevices = new ArrayList<>(); + for (Device device : devices) { + if (device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) { + activeDevices.add(device); + } + } + return activeDevices.size(); + } + return 0; + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return 0; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device getDevice(@PathParam("type") String type, @PathParam("identifier") String identifier){ + + try{ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(identifier); + deviceIdentifier.setType(type); + return this.getServiceProvider().getDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public DeviceType[] getDeviceTypes(){ + try{ + List deviceTypes = this.getServiceProvider().getAvailableDeviceTypes(); + return deviceTypes.toArray(new DeviceType[deviceTypes.size()]); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getAllDevices(@PathParam("type") String type){ + try{ + List devices = this.getServiceProvider().getAllDevices(type); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getAllDevices(){ + try{ + List devices = this.getServiceProvider().getAllDevices(); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/enrollment/invitation") + @POST + @Consumes("application/json") + @Produces("application/json") + public void sendEnrolmentInvitation(@FormParam("messageBody") String messageBody, + @FormParam("mailTo") String[] mailTo, @FormParam("ccList") String[] ccList, + @FormParam("bccList") String[] bccList, @FormParam("subject") String subject, + @FormParam("firstName") String firstName, @FormParam("enrolmentUrl") String enrolmentUrl, + @FormParam("title") String title, @FormParam("password") String password, + @FormParam("userName") String userName){ + EmailMessageProperties config = new EmailMessageProperties(); + config.setMessageBody(messageBody); + config.setMailTo(mailTo); + config.setCcList(ccList); + config.setBccList(bccList); + config.setSubject(subject); + config.setFirstName(firstName); + config.setEnrolmentUrl(enrolmentUrl); + config.setTitle(title); + config.setUserName(userName); + config.setPassword(password); + try { + this.getServiceProvider().sendEnrolmentInvitation(config); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/registration/invitation") + @POST + @Consumes("application/json") + @Produces("application/json") + public void sendRegistrationEmail(@FormParam("messageBody") String messageBody, + @FormParam("mailTo") String[] mailTo, @FormParam("ccList") String[] ccList, + @FormParam("bccList") String[] bccList, @FormParam("subject") String subject, + @FormParam("firstName") String firstName, @FormParam("enrolmentUrl") String enrolmentUrl, + @FormParam("title") String title, @FormParam("password") String password, + @FormParam("userName") String userName){ + EmailMessageProperties config = new EmailMessageProperties(); + config.setMessageBody(messageBody); + config.setMailTo(mailTo); + config.setCcList(ccList); + config.setBccList(bccList); + config.setSubject(subject); + config.setFirstName(firstName); + config.setEnrolmentUrl(enrolmentUrl); + config.setTitle(title); + config.setUserName(userName); + config.setPassword(password); + try { + this.getServiceProvider().sendRegistrationEmail(config); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/config") + @GET + @Consumes("application/json") + @Produces("application/json") + public TenantConfiguration getConfiguration(@PathParam("type") String type){ + try { + return this.getServiceProvider().getConfiguration(type); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/role/{role}/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getAllDevicesOfRole(@PathParam("role") String roleName){ + try{ + List devices = this.getServiceProvider().getAllDevicesOfRole(roleName); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/name/{name}/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getDevicesByName(@PathParam("name") String name) { + try{ + List devices = this.getServiceProvider().getDevicesByName(name); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/status") + @PUT + @Consumes("application/json") + @Produces("application/json") + void updateDeviceEnrolmentInfo(@PathParam("type") String type, @PathParam("identifier") String identifier, + @FormParam("status") EnrolmentInfo.Status status) { + DeviceManagementProviderService providerService = this.getServiceProvider(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + Device device = providerService.getDevice(deviceIdentifier); + providerService.updateDeviceEnrolmentInfo(device, status); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/status/{status}/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getDevicesByStatus(@PathParam("status") EnrolmentInfo.Status status) { + try{ + List devices = this.getServiceProvider().getDevicesByStatus(status); + return this.getActiveDevices(devices); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/license") + @GET + @Consumes("application/json") + @Produces("application/json") + public License getLicense(@PathParam("type") String type, @QueryParam("languageCode") String languageCode) { + try{ + return this.getServiceProvider().getLicense(type, languageCode); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/license") + @POST + @Consumes("application/json") + @Produces("application/json") + public void addLicense(@PathParam("type") String type, @FormParam("provider") String provider, + @FormParam("name") String name, @FormParam("version") String version, + @FormParam("language") String language, @FormParam("validFrom") Date validFrom, + @FormParam("validTo") Date validTo, @FormParam("text") String text) { + try{ + License license = new License(); + license.setProvider(provider); + license.setName(name); + license.setVersion(version); + license.setLanguage(language); + license.setValidFrom(validFrom); + license.setValidTo(validTo); + license.setText(text); + this.getServiceProvider().addLicense(type, license); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}") + @PUT + @Consumes("application/json") + @Produces("application/json") + boolean modifyEnrollment(@PathParam("type") String type, @PathParam("identifier") String identifier, + @FormParam("name") String name, @FormParam("description") String description, + @FormParam("groupId") int groupId, @FormParam("enrollmentId") int enrollmentId, + @FormParam("dateOfEnrolment") long dateOfEnrolment, @FormParam("dateOfLastUpdate") long dateOfLastUpdate, + @FormParam("ownership") EnrolmentInfo.OwnerShip ownership, @FormParam("status") EnrolmentInfo.Status status, + @FormParam("owner") String owner){ + + EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); + enrolmentInfo.setId(enrollmentId); + enrolmentInfo.setDateOfEnrolment(dateOfEnrolment); + enrolmentInfo.setDateOfLastUpdate(dateOfLastUpdate); + enrolmentInfo.setOwnership(ownership); + enrolmentInfo.setStatus(status); + enrolmentInfo.setOwner(owner); + + Device device = new Device(); + device.setType(type); + device.setDeviceIdentifier(identifier); + device.setName(name); + device.setDescription(description); + device.setGroupId(groupId); + device.setEnrolmentInfo(enrolmentInfo); + try { + return this.getServiceProvider().modifyEnrollment(device); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device") + @POST + @Consumes("application/json") + @Produces("application/json") + boolean enrollDevice(@FormParam("type") String type, @FormParam("identifier") String identifier, + @FormParam("name") String name, @FormParam("description") String description, + @FormParam("groupId") int groupId, @FormParam("enrollmentId") int enrollmentId, + @FormParam("dateOfEnrolment") long dateOfEnrolment, @FormParam("dateOfLastUpdate") long dateOfLastUpdate, + @FormParam("ownership") EnrolmentInfo.OwnerShip ownership, @FormParam("status") EnrolmentInfo.Status status, + @FormParam("owner") String owner){ + + EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); + enrolmentInfo.setId(enrollmentId); + enrolmentInfo.setDateOfEnrolment(dateOfEnrolment); + enrolmentInfo.setDateOfLastUpdate(dateOfLastUpdate); + enrolmentInfo.setOwnership(ownership); + enrolmentInfo.setStatus(status); + enrolmentInfo.setOwner(owner); + + Device device = new Device(); + device.setType(type); + device.setDeviceIdentifier(identifier); + device.setName(name); + device.setDescription(description); + device.setGroupId(groupId); + device.setEnrolmentInfo(enrolmentInfo); + try { + return this.getServiceProvider().enrollDevice(device); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/tenantconfiguration") + @GET + @Consumes("application/json") + @Produces("application/json") + public TenantConfiguration getConfiguration(){ + try { + return this.getServiceProvider().getConfiguration(); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/tenantconfiguration") + @POST + @Consumes("application/json") + @Produces("application/json") + public boolean saveConfiguration(@FormParam("tenantConfiguration") TenantConfiguration tenantConfiguration){ + try { + return this.getServiceProvider().saveConfiguration(tenantConfiguration); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}") + @DELETE + @Consumes("application/json") + @Produces("application/json") + public boolean disenrollDevice(@PathParam("type") String type, @PathParam("identifier") String identifier){ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + return this.getServiceProvider().disenrollDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/enrolled") + @GET + @Consumes("application/json") + @Produces("application/json") + public boolean isEnrolled(@PathParam("type") String type, @PathParam("identifier") String identifier){ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + return this.getServiceProvider().isEnrolled(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + @Path("/device/type/{type}/identifier/{identifier}/active") + @GET + @Consumes("application/json") + @Produces("application/json") + public boolean isActive(@PathParam("type") String type, @PathParam("identifier") String identifier){ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + return this.getServiceProvider().isActive(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/active") + @PUT + @Consumes("application/json") + @Produces("application/json") + public boolean setActive(@PathParam("type") String type, @PathParam("identifier") String identifier, + @FormParam("status") boolean status){ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + return this.getServiceProvider().setActive(deviceIdentifier, status); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/ownership") + @PUT + @Consumes("application/json") + @Produces("application/json") + public boolean setOwnership(@PathParam("type") String type, @PathParam("identifier") String identifier, + @FormParam("ownership") String ownership){ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + return this.getServiceProvider().setOwnership(deviceIdentifier, ownership); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/status") + @PUT + @Consumes("application/json") + @Produces("application/json") + public boolean setStatus(@PathParam("type") String type, @PathParam("identifier") String identifier, + @FormParam("owner") String owner, @FormParam("status") EnrolmentInfo.Status status){ + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(type); + deviceIdentifier.setId(identifier); + try { + return this.getServiceProvider().setStatus(deviceIdentifier, owner, status); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/sensor/{sensorName}") + @POST + @Consumes("application/json") + @Produces("application/json") + public boolean setSensorValue(@PathParam("type") String type, @PathParam("identifier") String deviceId, + @PathParam("sensorName") String sensorName, + @HeaderParam("sensorValue") String sensorValue){ + + try { + return SensorDataManager.getInstance().setSensorRecord(deviceId, sensorName, sensorValue, Calendar + .getInstance().getTimeInMillis()); + } finally { + this.endTenantFlow(); + } + } + + @Path("/device/type/{type}/identifier/{identifier}/sensor/{sensorName}") + @GET + @Consumes("application/json") + @Produces("application/json") + public SensorRecord getSensorValue(@PathParam("type") String type, @PathParam("identifier") String deviceId, + @PathParam("sensorName") String sensorName, @HeaderParam("defaultValue") String defaultValue){ + + try { + return SensorDataManager.getInstance().getSensorRecord(deviceId, sensorName); + } catch (DeviceControllerException e) { + log.error("Error on reading sensor value: " + e.getMessage()); + if(defaultValue != null){ + return new SensorRecord(defaultValue, Calendar.getInstance().getTimeInMillis()); + }else{ + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } + } finally { + this.endTenantFlow(); + } + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java new file mode 100644 index 000000000..496410386 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java @@ -0,0 +1,584 @@ +/* + * 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.wso2.carbon.device.mgt.iot.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.PaginationRequest; +import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.device.mgt.group.common.DeviceGroup; +import org.wso2.carbon.device.mgt.group.common.GroupManagementException; +import org.wso2.carbon.device.mgt.group.common.GroupUser; +import org.wso2.carbon.device.mgt.group.core.providers.GroupManagementServiceProvider; +import org.wso2.carbon.device.mgt.iot.util.ResponsePayload; + +import javax.jws.WebService; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +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.Response; +import java.util.Date; +import java.util.List; + +@WebService +public class GroupManagerService { + + private static final String DEFAULT_ADMIN_ROLE = "admin"; + private static final String DEFAULT_OPERATOR_ROLE = "invoke-device-operations"; + private static final String DEFAULT_STATS_MONITOR_ROLE = "view-statistics"; + private static final String DEFAULT_VIEW_POLICIES = "view-policies"; + private static final String DEFAULT_MANAGE_POLICIES = "mange-policies"; + private static final String DEFAULT_VIEW_EVENTS = "view-events"; + private static final String[] DEFAULT_ADMIN_PERMISSIONS = {"/permission/device-mgt/admin/groups", + "/permission/device-mgt/user/groups"}; + private static final String[] DEFAULT_OPERATOR_PERMISSIONS = {"/permission/device-mgt/user/groups/device_operation"}; + private static final String[] DEFAULT_STATS_MONITOR_PERMISSIONS = {"/permission/device-mgt/user/groups/device_monitor"}; + private static final String[] DEFAULT_MANAGE_POLICIES_PERMISSIONS = {"/permission/device-mgt/user/groups/device_policies/add"}; + private static final String[] DEFAULT_VIEW_POLICIES_PERMISSIONS = {"/permission/device-mgt/user/groups/device_policies/view"}; + private static final String[] DEFAULT_VIEW_EVENTS_PERMISSIONS = {"/permission/device-mgt/user/groups/device_events"}; + + private static Log log = LogFactory.getLog(GroupManagerService.class); + + @Context //injected response proxy supporting multiple threads + private HttpServletResponse response; + private PrivilegedCarbonContext ctx; + + private GroupManagementServiceProvider getServiceProvider() { + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String username = CarbonContext.getThreadLocalCarbonContext().getUsername(); + PrivilegedCarbonContext.startTenantFlow(); + ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain(tenantDomain, true); + if (log.isDebugEnabled()) { + log.debug("Getting thread local carbon context for tenant domain: " + tenantDomain); + } + return (GroupManagementServiceProvider) ctx.getOSGiService(GroupManagementServiceProvider.class, null); + } + + private void endTenantFlow() { + PrivilegedCarbonContext.endTenantFlow(); + ctx = null; + if (log.isDebugEnabled()) { + log.debug("Tenant flow ended"); + } + } + + @Path("/group") + @POST + @Consumes("application/json") + @Produces("application/json") + public Response createGroup(@FormParam("name") String name, + @FormParam("username") String username, + @FormParam("description") String description) { + DeviceGroup group = new DeviceGroup(); + group.setName(name); + group.setDescription(description); + group.setOwner(username); + group.setDateOfCreation(new Date().getTime()); + group.setDateOfLastUpdate(new Date().getTime()); + boolean isAdded = false; + try { + GroupManagementServiceProvider groupManagementService = this.getServiceProvider(); + int groupId = groupManagementService.createGroup(group, DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_PERMISSIONS); + if (groupId == -2) { + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_CONFLICT); + responsePayload.setMessageFromServer("Group name is already exists."); + responsePayload.setResponseContent("CONFLICT"); + return Response.status(HttpStatus.SC_CONFLICT).entity(responsePayload).build(); + } else { + isAdded = (groupId > 0) && groupManagementService.addGroupSharingRole(username, groupId, + DEFAULT_OPERATOR_ROLE, + DEFAULT_OPERATOR_PERMISSIONS); + groupManagementService.addGroupSharingRole(username, groupId, DEFAULT_STATS_MONITOR_ROLE, + DEFAULT_STATS_MONITOR_PERMISSIONS); + groupManagementService.addGroupSharingRole(username, groupId, DEFAULT_VIEW_POLICIES, + DEFAULT_VIEW_POLICIES_PERMISSIONS); + groupManagementService.addGroupSharingRole(username, groupId, DEFAULT_MANAGE_POLICIES, + DEFAULT_MANAGE_POLICIES_PERMISSIONS); + groupManagementService.addGroupSharingRole(username, groupId, DEFAULT_VIEW_EVENTS, + DEFAULT_VIEW_EVENTS_PERMISSIONS); + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + } catch (GroupManagementException e) { + return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } finally { + this.endTenantFlow(); + } + } + + @Path("/group/id/{groupId}") + @PUT + @Consumes("application/json") + @Produces("application/json") + public boolean updateGroup(@PathParam("groupId") int groupId, @FormParam("name") String name, + @FormParam("username") String username, + @FormParam("description") String description) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/modify")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + try { + GroupManagementServiceProvider groupManagementService = this.getServiceProvider(); + DeviceGroup group = groupManagementService.getGroup(groupId); + group.setName(name); + group.setDescription(description); + group.setOwner(username); + group.setDateOfLastUpdate(new Date().getTime()); + response.setStatus(Response.Status.OK.getStatusCode()); + groupManagementService.updateGroup(group); + return true; + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + return false; + } finally { + this.endTenantFlow(); + } + } + + @Path("/group/id/{groupId}") + @DELETE + @Consumes("application/json") + @Produces("application/json") + public boolean deleteGroup(@PathParam("groupId") int groupId, + @QueryParam("username") String username) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/delete")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + boolean isDeleted = false; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + isDeleted = this.getServiceProvider().deleteGroup(groupId); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isDeleted; + } + + @Path("/group/id/{groupId}") + @GET + @Consumes("application/json") + @Produces("application/json") + public DeviceGroup getGroup(@PathParam("groupId") int groupId, + @FormParam("username") String username) { + DeviceGroup deviceGroup = null; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + deviceGroup = this.getServiceProvider().getGroup(groupId); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return deviceGroup; + } + + @Path("/group/name/{groupName}") + @GET + @Consumes("application/json") + @Produces("application/json") + public DeviceGroup[] findGroups(@PathParam("groupName") String groupName, + @FormParam("username") String username) { + DeviceGroup[] deviceGroups = null; + try { + List groups = this.getServiceProvider().findGroups(groupName, username); + deviceGroups = new DeviceGroup[groups.size()]; + response.setStatus(Response.Status.OK.getStatusCode()); + groups.toArray(deviceGroups); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return deviceGroups; + } + + @Path("/group/user/{username}/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public DeviceGroup[] getGroups(@PathParam("username") String username, + @QueryParam("permission") String permission) { + DeviceGroup[] deviceGroups = null; + try { + GroupManagementServiceProvider groupManagementService = this.getServiceProvider(); + List groups; + if (permission != null) { + groups = groupManagementService.getGroups(username, permission); + } else { + groups = groupManagementService.getGroups(username); + } + deviceGroups = new DeviceGroup[groups.size()]; + response.setStatus(Response.Status.OK.getStatusCode()); + groups.toArray(deviceGroups); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return deviceGroups; + } + + @Path("/group/user/{username}/all/count") + @GET + @Consumes("application/json") + @Produces("application/json") + public int getGroupCount(@PathParam("username") String username) { + int count = -1; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + count = this.getServiceProvider().getGroupCount(username); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return count; + } + + @Path("/group/id/{groupId}/share") + @POST + @Consumes("application/json") + @Produces("application/json") + public boolean shareGroup(@FormParam("username") String username, + @FormParam("shareUser") String shareUser, + @PathParam("groupId") int groupId, + @FormParam("role") String sharingRole) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/share")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + boolean isShared = false; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + isShared = this.getServiceProvider().shareGroup(shareUser, groupId, sharingRole); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isShared; + } + + @Path("/group/id/{groupId}/unshare") + @POST + @Consumes("application/json") + @Produces("application/json") + public boolean unShareGroup(@FormParam("username") String username, + @FormParam("unShareUser") String unShareUser, + @PathParam("groupId") int groupId, + @FormParam("role") String sharingRole) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/share")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + boolean isUnShared = false; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + isUnShared = this.getServiceProvider().unshareGroup(unShareUser, groupId, sharingRole); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isUnShared; + } + + @Path("/group/id/{groupId}/role") + @POST + @Consumes("application/json") + @Produces("application/json") + public boolean addSharing(@FormParam("username") String username, + @PathParam("groupId") int groupId, + @FormParam("role") String roleName, + @FormParam("permissions") String[] permissions) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/share")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + boolean isAdded = false; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + isAdded = this.getServiceProvider().addGroupSharingRole(username, groupId, roleName, permissions); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isAdded; + } + + @Path("/group/id/{groupId}/role/{role}") + @DELETE + @Consumes("application/json") + @Produces("application/json") + public boolean removeSharing(@QueryParam("username") String username, + @PathParam("groupId") int groupId, + @PathParam("role") String roleName) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/share")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + } + boolean isRemoved = false; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + isRemoved = this.getServiceProvider().removeGroupSharingRole(groupId, roleName); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isRemoved; + } + + @Path("/group/id/{groupId}/role/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public String[] getRoles(@PathParam("groupId") int groupId) { + String[] rolesArray = null; + try { + List roles = this.getServiceProvider().getRoles(groupId); + rolesArray = new String[roles.size()]; + response.setStatus(Response.Status.OK.getStatusCode()); + roles.toArray(rolesArray); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return rolesArray; + } + + @Path("/group/id/{groupId}/{user}/role/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public String[] getRoles(@PathParam("user") String user, @PathParam("groupId") int groupId) { + String[] rolesArray = null; + try { + List roles = this.getServiceProvider().getRoles(user, groupId); + rolesArray = new String[roles.size()]; + response.setStatus(Response.Status.OK.getStatusCode()); + roles.toArray(rolesArray); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return rolesArray; + } + + @Path("/group/id/{groupId}/user/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public GroupUser[] getUsers(@PathParam("groupId") int groupId) { + GroupUser[] usersArray = null; + try { + List users = this.getServiceProvider().getUsers(groupId); + usersArray = new GroupUser[users.size()]; + response.setStatus(Response.Status.OK.getStatusCode()); + users.toArray(usersArray); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return usersArray; + } + + @Path("/group/id/{groupId}/device/all") + @GET + @Consumes("application/json") + @Produces("application/json") + public Device[] getDevices(@PathParam("groupId") int groupId) { + Device[] deviceArray = null; + try { + List devices = this.getServiceProvider().getDevices(groupId); + deviceArray = new Device[devices.size()]; + response.setStatus(Response.Status.OK.getStatusCode()); + devices.toArray(deviceArray); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return deviceArray; + } + + @Path("/group/id/{groupId}/device/count") + @GET + @Consumes("application/json") + @Produces("application/json") + public int getDeviceCount(@PathParam("groupId") int groupId) { + try { + return this.getServiceProvider().getDeviceCount(groupId); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + return -1; + } finally { + this.endTenantFlow(); + } + } + + @Path("/group/id/{groupId}/device") + @GET + @Consumes("application/json") + @Produces("application/json") + public PaginationResult getDevices(@PathParam("groupId") int groupId, + @QueryParam("index") int index, + @QueryParam("limit") int limit) { + try { + PaginationRequest request = new PaginationRequest(index, limit); + return this.getServiceProvider().getDevices(groupId, request); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + return null; + } finally { + this.endTenantFlow(); + } + } + + @Path("/group/id/{groupId}/device/assign") + @PUT + @Consumes("application/json") + @Produces("application/json") + public boolean addDevice(@PathParam("groupId") int groupId, + @FormParam("deviceId") String deviceId, + @FormParam("deviceType") String deviceType, + @FormParam("username") String username) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/add_devices")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + boolean isAdded = false; + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId, deviceType); + response.setStatus(Response.Status.OK.getStatusCode()); + isAdded = this.getServiceProvider().addDevice(deviceIdentifier, groupId); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isAdded; + } + + @Path("/group/id/{groupId}/device/assign") + @DELETE + @Consumes("application/json") + @Produces("application/json") + public boolean removeDevice(@PathParam("groupId") int groupId, + @FormParam("deviceId") String deviceId, + @FormParam("deviceType") String deviceType, + @FormParam("username") String username) { + if (!isAuthorized(username, groupId, "/permission/device-mgt/admin/groups/remove_devices")) { + response.setStatus(Response.Status.FORBIDDEN.getStatusCode()); + return false; + } + boolean isRemoved = false; + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId, deviceType); + response.setStatus(Response.Status.OK.getStatusCode()); + isRemoved = this.getServiceProvider().removeDevice(deviceIdentifier, groupId); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isRemoved; + } + + @Path("/group/id/{groupId}/user/{username}/permissions") + @GET + @Consumes("application/json") + @Produces("application/json") + public String[] getPermissions(@PathParam("username") String username, + @PathParam("groupId") int groupId) { + String[] permissions = null; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + permissions = this.getServiceProvider().getPermissions(username, groupId); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return permissions; + } + + @Path("/group/id/{groupId}/user/{username}/authorized") + @GET + @Consumes("application/json") + @Produces("application/json") + public boolean isAuthorized(@PathParam("username") String username, + @PathParam("groupId") int groupId, + @QueryParam("permission") String permission) { + boolean isAuthorized = false; + try { + response.setStatus(Response.Status.OK.getStatusCode()); + isAuthorized = this.getServiceProvider().isAuthorized(username, groupId, permission); + } catch (GroupManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + } finally { + this.endTenantFlow(); + } + return isAuthorized; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/PolicyManagementService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/PolicyManagementService.java new file mode 100644 index 000000000..702ea89ed --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/PolicyManagementService.java @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.policy.mgt.common.Policy; +import org.wso2.carbon.policy.mgt.common.PolicyAdministratorPoint; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.common.PolicyMonitoringTaskException; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceData; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; +import org.wso2.carbon.policy.mgt.core.task.TaskScheduleService; + +import javax.jws.WebService; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import java.util.List; + +@WebService +public class PolicyManagementService { + + private static Log log = LogFactory.getLog(PolicyManagementService.class); + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + + private PrivilegedCarbonContext ctx; + + private PolicyManagerService getPolicyServiceProvider() throws DeviceManagementException { + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + PrivilegedCarbonContext.startTenantFlow(); + ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain(tenantDomain, true); + + if (log.isDebugEnabled()) { + log.debug("Getting thread local carbon context for tenant domain: " + tenantDomain); + } + + PolicyManagerService policyManagerService = (PolicyManagerService) ctx.getOSGiService( + PolicyManagerService.class, null); + + if (policyManagerService == null) { + String msg = "Policy Management service not initialized"; + log.error(msg); + throw new DeviceManagementException(msg); + } + + return policyManagerService; + } + + private void endTenantFlow() { + PrivilegedCarbonContext.endTenantFlow(); + ctx = null; + if (log.isDebugEnabled()) { + log.debug("Tenant flow ended"); + } + } + + @POST + @Path("/inactive-policy") + @Produces("application/json") + public boolean addPolicy(Policy policy) { + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + pap.addPolicy(policy); + response.setStatus(Response.Status.CREATED.getStatusCode()); + if (log.isDebugEnabled()) { + log.debug("Policy has been added successfully."); + } + return true; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @POST + @Path("/active-policy") + @Produces("application/json") + public boolean addActivePolicy(Policy policy) { + + policy.setActive(true); + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + pap.addPolicy(policy); + response.setStatus(Response.Status.CREATED.getStatusCode()); + if (log.isDebugEnabled()) { + log.debug("Policy has been added successfully."); + } + return true; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Produces("application/json") + public Policy[] getAllPolicies() { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint policyAdministratorPoint = policyManagerService.getPAP(); + List policies = policyAdministratorPoint.getPolicies(); + return policyAdministratorPoint.getPolicies().toArray(new Policy[policies.size()]); + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Produces("application/json") + @Path("/{id}") + public Policy getPolicy(@PathParam("id") int policyId) { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint policyAdministratorPoint = policyManagerService.getPAP(); + Policy policy = policyAdministratorPoint.getPolicy(policyId); + if (policy != null) { + if (log.isDebugEnabled()) { + log.debug("Sending policy for ID " + policyId); + } + return policy; + } else { + log.error("Policy for ID " + policyId + " not found."); + response.setStatus(Response.Status.NOT_FOUND.getStatusCode()); + return null; + } + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Path("/count") + public int getPolicyCount() { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint policyAdministratorPoint = policyManagerService.getPAP(); + return policyAdministratorPoint.getPolicyCount(); + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return -1; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return -1; + } finally { + this.endTenantFlow(); + } + } + + @PUT + @Path("/{id}") + @Produces("application/json") + public boolean updatePolicy(Policy policy, @PathParam("id") int policyId) { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + Policy previousPolicy = pap.getPolicy(policyId); + policy.setProfile(pap.getProfile(previousPolicy.getProfileId())); + policy.setPolicyName(previousPolicy.getPolicyName()); + pap.updatePolicy(policy); + if (log.isDebugEnabled()) { + log.debug("Policy with ID " + policyId + " has been updated successfully."); + } + return true; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @PUT + @Path("/priorities") + @Consumes("application/json") + @Produces("application/json") + public boolean updatePolicyPriorities(List priorityUpdatedPolicies) { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + boolean policiesUpdated = pap.updatePolicyPriorities(priorityUpdatedPolicies); + if (policiesUpdated) { + if (log.isDebugEnabled()) { + log.debug("Policy Priorities successfully updated."); + } + return true; + } else { + if (log.isDebugEnabled()) { + log.debug("Policy priorities did not update. Bad Request."); + } + response.setStatus(Response.Status.BAD_REQUEST.getStatusCode()); + return false; + } + } catch (PolicyManagementException e) { + String error = "Exception in updating policy priorities."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @DELETE + @Path("/{id}") + @Produces("application/json") + public boolean deletePolicy(@PathParam("id") int policyId) { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + Policy policy = pap.getPolicy(policyId); + boolean policyDeleted = pap.deletePolicy(policy); + if (policyDeleted) { + if (log.isDebugEnabled()) { + log.debug("Policy by id:" + policyId + " has been successfully deleted."); + } + return true; + } else { + if (log.isDebugEnabled()) { + log.debug("Policy by id:" + policyId + " does not exist."); + } + response.setStatus(Response.Status.NOT_FOUND.getStatusCode()); + return false; + } + } catch (PolicyManagementException e) { + String error = "Exception in deleting policy by id:" + policyId; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @PUT + @Produces("application/json") + @Path("/activate/{id}") + public boolean activatePolicy(@PathParam("id") int policyId) { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + pap.activatePolicy(policyId); + if (log.isDebugEnabled()) { + log.debug("Policy by id:" + policyId + " has been successfully activated."); + } + return true; + } catch (PolicyManagementException e) { + String error = "Exception in activating policy by id:" + policyId; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @PUT + @Produces("application/json") + @Path("/inactivate/{id}") + public boolean inactivatePolicy(@PathParam("id") int policyId) { + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + pap.inactivatePolicy(policyId); + if (log.isDebugEnabled()) { + log.debug("Policy by id:" + policyId + " has been successfully inactivated."); + } + return true; + } catch (PolicyManagementException e) { + String error = "Exception in inactivating policy by id:" + policyId; + log.error(error, e); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @PUT + @Produces("application/json") + @Path("/apply-changes") + public boolean applyChanges() { + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + PolicyAdministratorPoint pap = policyManagerService.getPAP(); + pap.publishChanges(); + if (log.isDebugEnabled()) { + log.debug("Changes have been successfully updated."); + } + return true; + } catch (PolicyManagementException e) { + String error = "Exception in applying changes."; + log.error(error, e); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Path("/start-task/{milliseconds}") + public boolean startTaskService(@PathParam("milliseconds") int monitoringFrequency) { + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + TaskScheduleService taskScheduleService = policyManagerService.getTaskScheduleService(); + taskScheduleService.startTask(monitoringFrequency); + if (log.isDebugEnabled()) { + log.debug("Policy monitoring service started successfully."); + } + return true; + } catch (PolicyMonitoringTaskException e) { + String error = "Policy Management related exception."; + log.error(error, e); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Path("/update-task/{milliseconds}") + public boolean updateTaskService(@PathParam("milliseconds") int monitoringFrequency) { + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + TaskScheduleService taskScheduleService = policyManagerService.getTaskScheduleService(); + taskScheduleService.updateTask(monitoringFrequency); + if (log.isDebugEnabled()) { + log.debug("Policy monitoring service updated successfully."); + } + return true; + } catch (PolicyMonitoringTaskException e) { + String error = "Policy Management related exception."; + log.error(error, e); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Path("/stop-task") + public boolean stopTaskService() { + + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + TaskScheduleService taskScheduleService = policyManagerService.getTaskScheduleService(); + taskScheduleService.stopTask(); + if (log.isDebugEnabled()) { + log.debug("Policy monitoring service stopped successfully."); + } + return true; + } catch (PolicyMonitoringTaskException e) { + String error = "Policy Management related exception."; + log.error(error, e); + return false; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + this.endTenantFlow(); + } + } + + @GET + @Path("/{type}/{id}") + public ComplianceData getComplianceDataOfDevice(@PathParam("id") String deviceId, + @PathParam("type") String deviceType) { + try { + PolicyManagerService policyManagerService = getPolicyServiceProvider(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(deviceType); + deviceIdentifier.setId(deviceId); + return policyManagerService.getDeviceCompliance(deviceIdentifier); + } catch (PolicyComplianceException e) { + String error = "Error occurred while getting the compliance data."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } catch (DeviceManagementException e) { + String error = "Error occurred while invoking Policy Management Service."; + log.error(error, e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + this.endTenantFlow(); + } + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java new file mode 100644 index 000000000..4c696654a --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.common.AnalyticsDataRecord; +import org.wso2.carbon.device.mgt.analytics.exception.DeviceManagementAnalyticsException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +import javax.jws.WebService; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +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.Response; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +@WebService public class StatsManagerService { + + private static Log log = LogFactory.getLog(StatsManagerService.class); + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + //TODO THIS NEEDS TO BE REMOVED. + @Path("/stats/device/type/{type}/identifier/{identifier}") + @GET + @Consumes("application/json") + @Produces("application/json") + public DeviceUsageDTO[] getDeviceStats(@PathParam("type") String type, @PathParam("identifier") String identifier, + @QueryParam("table") String table, @QueryParam("column") String column, @QueryParam("username") String user, + @QueryParam("from") long from, @QueryParam("to") long to) { + + String fromDate = String.valueOf(from); + String toDate = String.valueOf(to); + + List deviceUsageDTOs = new ArrayList<>(); + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain("carbon.super", true); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + String query = "owner:" + user + " AND deviceId:" + identifier + " AND deviceType:" + type + + " AND time : [" + fromDate + " TO " + toDate + "]"; + try { + List records = deviceAnalyticsService.getAllEventsForDevice(table, query); + + Collections.sort(records, new Comparator() { + @Override + public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { + long t1 = (Long) o1.getValue("time"); + long t2 = (Long) o2.getValue("time"); + if (t1 < t2) { + return -1; + } else if (t1 > t2) { + return 1; + } else { + return 0; + } + } + }); + + for (AnalyticsDataRecord record : records) { + DeviceUsageDTO deviceUsageDTO = new DeviceUsageDTO(); + deviceUsageDTO.setTime("" + (long)record.getValue("time")); + deviceUsageDTO.setValue("" + (float) record.getValue(column.toLowerCase())); + deviceUsageDTOs.add(deviceUsageDTO); + } + return deviceUsageDTOs.toArray(new DeviceUsageDTO[deviceUsageDTOs.size()]); + } catch (DeviceManagementAnalyticsException e) { + String errorMsg= "Error on retrieving stats on table " + table + " with query " + query; + log.error(errorMsg); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return deviceUsageDTOs.toArray(new DeviceUsageDTO[deviceUsageDTOs.size()]); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/util/ResponsePayload.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/util/ResponsePayload.java new file mode 100644 index 000000000..c37d1d3a0 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/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.wso2.carbon.device.mgt.iot.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 ResponsePayloadBuilder statusCode(int statusCode) { + ResponsePayload message = new ResponsePayload(); + return message.getBuilder().statusCode(statusCode); + } + + public static ResponsePayloadBuilder messageFromServer( + String messageFromServer) { + ResponsePayload message = new ResponsePayload(); + return message.getBuilder().messageFromServer(messageFromServer); + } + + public static 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 ResponsePayloadBuilder getBuilder() { + return new 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/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/permissions.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..aa291109e --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,113 @@ + + + + + + + + + Get Device of user + /login + /device_manager/device/user/{username}/all + GET + + + + + Get ungrouped devices of user + /login + /device_manager/device/user/{username}/ungrouped + GET + + + + + Get Device of user + /login + /device_manager/device_manager/device/user/{username}/ungrouped + GET + + + + + Get count of all the devices + /login + /device_manager/device/user/{username}/all/count + GET + + + + + Get specific device + /login + /device_manager/device/type/{type}/identifier/{identifier} + GET + + + + + Get the device type + /login + /device_manager/device/type/all + GET + + + + + Get all devices + /login + /device_manager/device/all + GET + + + + + Get the device by name + /login + /device_manager/device/name/{name}/all + GET + + + + + Update device enrollment info + /login + /device_manager/device/type/{type}/identifier/{identifier}/status + GET + + + + + Update device enrollment info + /login + /device_manager/device/type/{type}/identifier/{identifier}/status + GET + + + + \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..1112d721e --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/web.xml new file mode 100755 index 000000000..433526519 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,27 @@ + + + WSO2 IoT Server + WSO2 IoT Server + + + CXFServlet + org.apache.cxf.transport.servlet.CXFServlet + 1 + + + CXFServlet + /* + + + isAdminService + false + + + doAuthentication + true + + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/pom.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/pom.xml new file mode 100644 index 000000000..2d8b71102 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + iot-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.ui + WSO2 Carbon - IoT Server UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/assembly/src.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/app-conf.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/app-conf.json new file mode 100644 index 000000000..6d4d99825 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/conf/app-conf.json @@ -0,0 +1,35 @@ +{ + "appName": "IoT Server", + "cachingEnabled": true, + "debuggingEnabled": false, + "permissionRoot": "/", + "loginPage": "cdmf.page.sign-in", + "adminServicesUrl": "https://${server.ip}:${server.https_port}/admin/services/", + "authModule": { + "enabled": true, + "login": { + "onSuccess": { + "script": "/app/modules/login.js", + "page": "cdmf.page.dashboard" + }, + "onFail": { + "script": "/app/modules/login.js", + "page": "cdmf.page.sign-in" + } + }, + "logout": { + "onSuccess": { + "page": "cdmf.page.sign-in" + }, + "onFail": { + "page": "cdmf.page.dashboard" + } + }, + "sso": { + "enabled": false + } + }, + "errorPages": { + "default": "uuf.page.error" + } +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/public/js/validate-register.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/public/js/validate-register.js new file mode 100644 index 000000000..ea67fcc83 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/public/js/validate-register.js @@ -0,0 +1,163 @@ +/* + * 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. + */ + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param inputString Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +function inputIsValid(regExp, inputString) { + regExp = new RegExp(regExp); + return regExp.test(inputString); +} + +/** + * Checks if an email address has the valid format or not. + * + * @param email Email address + * @returns {boolean} true if email has the valid format, otherwise false. + */ +function emailIsValid(email) { + var regExp = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; + return regExp.test(email); +} + +$(document).ready(function(){ + + /** + * Following click function would execute + * when a user clicks on "Add User" button + * on Add User page in WSO2 Devicemgt Console. + */ + $("button#add-user-btn").click(function () { + + var usernameInput = $("input#user_name"); + var firstnameInput = $("input#first_name"); + var lastnameInput = $("input#last_name"); + var emailInput = $("input#email"); + var passwordInput = $("input#password"); + var passwordConfirmationInput = $("input#password_confirmation"); + + var username = usernameInput.val().trim(); + var firstname = firstnameInput.val(); + var lastname = lastnameInput.val(); + var emailAddress = emailInput.val(); + var password = passwordInput.val(); + var passwordConfirmation = passwordConfirmationInput.val(); + var errorMsgWrapper = "#user-create-error-msg"; + var errorMsg = "#user-create-error-msg span"; + + if (!firstname) { + $(errorMsg).text("Firstname is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!inputIsValid(firstnameInput.data("regex"), firstname)) { + $(errorMsg).text(firstnameInput.data("errormsg")); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!lastname) { + $(errorMsg).text("Lastname is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!inputIsValid(lastnameInput.data("regex"), lastname)) { + $(errorMsg).text(lastnameInput.data("errormsg")); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!username) { + $(errorMsg).text("Username is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!inputIsValid(usernameInput.data("regex"), username)) { + $(errorMsg).text(usernameInput.data("errormsg")); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!emailAddress) { + $(errorMsg).text("Email is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!emailIsValid(emailAddress)) { + $(errorMsg).text(emailInput.data("errormsg")); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!password) { + $(errorMsg).text("Password is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (password.length < 6) { + $(errorMsg).text("Password is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (password != passwordConfirmation) { + $(errorMsg).text("Please enter the same password for confirmation."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + $(errorMsgWrapper).addClass("hidden"); + $("#add-user-btn").prop('disabled', true); + + var addUserFormData = {}; + addUserFormData.username = username; + addUserFormData.firstname = firstname; + addUserFormData.lastname = lastname; + addUserFormData.emailAddress = emailAddress; + addUserFormData.password = $("input#password").val(); + addUserFormData.userRoles = null; + + var context = $(".form-login-box").data("context"); + var addUserAPI = context + "/api/user/register"; + + $.ajax({ + type: 'POST', + url: addUserAPI, + contentType: 'application/json', + data: JSON.stringify(addUserFormData), + success: function (data) { + $("#add-user-btn").prop('disabled', false); + if (data == 200) { + $('.wr-validation-summary strong').html( + " Successfully Submitted."); + $('.wr-validation-summary').removeClass("alert-danger"); + $('.wr-validation-summary').addClass("alert-success"); + } else if (data == 201) { + $('.wr-validation-summary strong').html( + " User created succssfully. You will be " + + "redirected to login page."); + $('.wr-validation-summary').removeClass("alert-danger"); + $('.wr-validation-summary').addClass("alert-success"); + $("#add-user-btn").prop('disabled', true); + setTimeout(function () { + window.location = context + "/login"; + }, 2000); + } else if (data == 400) { + $('.wr-validation-summary strong').html( + " Exception at backend."); + $('.wr-validation-summary').removeClass("alert-danger"); + $('.wr-validation-summary').addClass("alert-warning"); + } else if (data == 403) { + $('.wr-validation-summary strong').html("Action not permitted."); + } else if (data == 409) { + $('.wr-validation-summary strong').html( + " User name already exists."); + $('.wr-validation-summary').removeClass("alert-default"); + $('.wr-validation-summary').addClass("alert-success"); + } + $('.wr-validation-summary').removeClass("hidden"); + $('#password').val(''); + $('#password_confirmation').val(''); + }, + error: function (err) { + $("#add-user-btn").prop('disabled', false); + $('.wr-validation-summary strong').html( + " An unexpected error occurred."); + $('.wr-validation-summary').removeClass("hidden"); + } + }); + } + }); +}); diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.hbs new file mode 100644 index 000000000..e68e3ef1d --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.hbs @@ -0,0 +1,75 @@ +{{unit "cdmf.unit.ui.title" pageTitle="Register"}} + +{{#zone "content"}} + {{unit "uuf.unit.lib.form-validation"}} + + +{{/zone}} + +{{#zone "bottomJs"}} + {{js "js/validate-register.js"}} +{{/zone}} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.js new file mode 100644 index 000000000..d0bdca27b --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.js @@ -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. + */ + +/** + * Returns the dynamic state to be populated by add-user page. + * + * @param context Object that gets updated with the dynamic state of this page to be presented + * @returns {*} A context object that returns the dynamic state of this page to be presented + */ +function onRequest(context) { + var devicemgtProps = require('/app/conf/devicemgt-props.js').config(); + var page = {}; + page["usernameJSRegEx"] = devicemgtProps.userValidationConfig.usernameJSRegEx; + page["usernameHelpText"] = devicemgtProps.userValidationConfig.usernameHelpMsg; + page["usernameRegExViolationErrorMsg"] = devicemgtProps.userValidationConfig.usernameRegExViolationErrorMsg; + page["firstnameJSRegEx"] = devicemgtProps.userValidationConfig.firstnameJSRegEx; + page["firstnameRegExViolationErrorMsg"] = devicemgtProps.userValidationConfig.firstnameRegExViolationErrorMsg; + page["lastnameJSRegEx"] = devicemgtProps.userValidationConfig.lastnameJSRegEx; + page["lastnameRegExViolationErrorMsg"] = devicemgtProps.userValidationConfig.lastnameRegExViolationErrorMsg; + page["emailJSRegEx"] = devicemgtProps.userValidationConfig.emailJSRegEx; + page["emailRegExViolationErrorMsg"] = devicemgtProps.userValidationConfig.emailRegExViolationErrorMsg; + return page; +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.json new file mode 100644 index 000000000..58346ba14 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.register/register.json @@ -0,0 +1,6 @@ +{ + "version": "1.0.0", + "uri": "/register", + "isAnonymous": true, + "layout": "uuf.layout.sign-in" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.hbs new file mode 100644 index 000000000..4ab4ff871 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.hbs @@ -0,0 +1,5 @@ +{{#zone "signInForm-below"}} + +{{/zone}} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.json new file mode 100644 index 000000000..dea3950ba --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/iot.page.sign-in/sign-in.json @@ -0,0 +1,4 @@ +{ +"version": "1.0.0", +"extends": "cdmf.page.sign-in" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.hbs new file mode 100644 index 000000000..bdeac1967 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.hbs @@ -0,0 +1,75 @@ +{{#if control_operations}} +
      + + {{#each control_operations}} + + {{#if icon}} + + {{else}} + + {{/if}} + {{name}} + + +
      +
      +
      +
      +

      + + + + + {{name}} +
      +

      +

      + {{description}} +
      +

      + +
      + {{#each params}} + +
      + {{/each}} + + + +
      +
      +
      +
      +
      + {{/each}} +
      +{{else}} +
      +

      + Operations Loading Failed!

      +
      +{{/if}} + +{{#zone "bottomJs"}} + {{js "js/operation-bar.js"}} +{{/zone}} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.js new file mode 100644 index 000000000..6a90314ea --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.js @@ -0,0 +1,31 @@ +/* + * 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("operation.js"); + var operationModule = require("/app/modules/operation.js").operationModule; + var device = context.unit.params.device; + var controlOperations; + try { + controlOperations = operationModule.getControlOperations(device.type); + }catch(e){ + log.error("Control operation loading failed."); + controlOperations = null; + } + return {"control_operations": controlOperations, "device": device}; +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.json new file mode 100644 index 000000000..688e93980 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/operation-bar.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/public/js/operation-bar.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/public/js/operation-bar.js new file mode 100644 index 000000000..efaa79aca --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.operation-bar/public/js/operation-bar.js @@ -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. + */ + +/* + * On operation click function. + * @param selection: Selected operation + */ +function operationSelect (selection) { + $(modalPopupContent).addClass("operation-data"); + $(modalPopupContent).html($(" .operation[data-operation-code=" + selection + "]").html()); + $(modalPopupContent).data("operation-code", selection); + showPopup(); +} + +$(document).on('submit', 'form', function (e) { + e.preventDefault(); + var postOperationRequest = $.ajax({ + url: $(this).attr("action") + '&' + $(this).serialize(), + method: "post" + }); + + var btnSubmit = $('#btnSend', this); + btnSubmit.addClass('hidden'); + + var lblSending = $('#lblSending', this); + lblSending.removeClass('hidden'); + + var lblSent = $('#lblSent', this); + postOperationRequest.done(function (data) { + lblSending.addClass('hidden'); + lblSent.removeClass('hidden'); + setTimeout(function () { + hidePopup(); + }, 3000); + }); + + postOperationRequest.fail(function (jqXHR, textStatus) { + lblSending.addClass('hidden'); + lblSent.addClass('hidden'); + }); +}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/css/graph.css b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/css/graph.css new file mode 100644 index 000000000..7d0c9bba1 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/css/graph.css @@ -0,0 +1,471 @@ +/* + * 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. + */ + +/* graph */ + +.rickshaw_graph { + position: relative; +} + +.rickshaw_graph svg { + display: block; + overflow: hidden; +} + +/* ticks */ + +.rickshaw_graph .x_tick { + position: absolute; + top: 0; + bottom: 0; + width: 0; + border-left: 1px dotted rgba(0, 0, 0, 0.2); + pointer-events: none; +} + +.rickshaw_graph .x_tick .title { + position: absolute; + font-size: 12px; + font-family: Arial, sans-serif; + opacity: 0.5; + white-space: nowrap; + margin-left: 3px; + bottom: -20px; + height: auto; + border-bottom: none; +} + +/* annotations */ + +.rickshaw_annotation_timeline { + height: 1px; + border-top: 1px solid #e0e0e0; + margin-top: 10px; + position: relative; +} + +.rickshaw_annotation_timeline .annotation { + position: absolute; + height: 6px; + width: 6px; + margin-left: -2px; + top: -3px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0.25); +} + +.rickshaw_graph .annotation_line { + position: absolute; + top: 0; + bottom: -6px; + width: 0; + border-left: 2px solid rgba(0, 0, 0, 0.3); + display: none; +} + +.rickshaw_graph .annotation_line.active { + display: block; +} + +.rickshaw_graph .annotation_range { + background: rgba(0, 0, 0, 0.1); + display: none; + position: absolute; + top: 0; + bottom: -6px; +} + +.rickshaw_graph .annotation_range.active { + display: block; +} + +.rickshaw_graph .annotation_range.active.offscreen { + display: none; +} + +.rickshaw_annotation_timeline .annotation .content { + background: white; + color: black; + opacity: 0.9; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.8); + border-radius: 3px; + position: relative; + z-index: 20; + font-size: 12px; + padding: 6px 8px 8px; + top: 18px; + left: -11px; + width: 160px; + display: none; + cursor: pointer; +} + +.rickshaw_annotation_timeline .annotation .content:before { + content: "\25b2"; + position: absolute; + top: -11px; + color: white; + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8); +} + +.rickshaw_annotation_timeline .annotation.active, +.rickshaw_annotation_timeline .annotation:hover { + background-color: rgba(0, 0, 0, 0.8); + cursor: none; +} + +.rickshaw_annotation_timeline .annotation .content:hover { + z-index: 50; +} + +.rickshaw_annotation_timeline .annotation.active .content { + display: block; +} + +.rickshaw_annotation_timeline .annotation:hover .content { + display: block; + z-index: 50; +} + +.rickshaw_graph .y_axis, +.rickshaw_graph .x_axis_d3 { + fill: none; +} + +.rickshaw_graph .y_ticks .tick line, +.rickshaw_graph .x_ticks_d3 .tick { + stroke: rgba(0, 0, 0, 0.16); + stroke-width: 2px; + shape-rendering: crisp-edges; + pointer-events: none; +} + +.rickshaw_graph .y_grid .tick, +.rickshaw_graph .x_grid_d3 .tick { + z-index: -1; + stroke: rgba(0, 0, 0, 0.20); + stroke-width: 1px; + stroke-dasharray: 1 1; +} + +.rickshaw_graph .y_grid .tick[data-y-value="0"] { + stroke-dasharray: 1 0; +} + +.rickshaw_graph .y_grid path, +.rickshaw_graph .x_grid_d3 path { + fill: none; + stroke: none; +} + +.rickshaw_graph .y_ticks path, +.rickshaw_graph .x_ticks_d3 path { + fill: none; + stroke: #808080; +} + +.rickshaw_graph .y_ticks text, +.rickshaw_graph .x_ticks_d3 text { + opacity: 0.5; + font-size: 12px; + pointer-events: none; +} + +.rickshaw_graph .x_tick.glow .title, +.rickshaw_graph .y_ticks.glow text { + fill: black; + color: black; + text-shadow: -1px 1px 0 rgba(255, 255, 255, 0.1), + 1px -1px 0 rgba(255, 255, 255, 0.1), + 1px 1px 0 rgba(255, 255, 255, 0.1), + 0 1px 0 rgba(255, 255, 255, 0.1), + 0 -1px 0 rgba(255, 255, 255, 0.1), + 1px 0 0 rgba(255, 255, 255, 0.1), + -1px 0 0 rgba(255, 255, 255, 0.1), + -1px -1px 0 rgba(255, 255, 255, 0.1); +} + +.rickshaw_graph .x_tick.inverse .title, +.rickshaw_graph .y_ticks.inverse text { + fill: white; + color: white; + text-shadow: -1px 1px 0 rgba(0, 0, 0, 0.8), + 1px -1px 0 rgba(0, 0, 0, 0.8), + 1px 1px 0 rgba(0, 0, 0, 0.8), + 0 1px 0 rgba(0, 0, 0, 0.8), + 0 -1px 0 rgba(0, 0, 0, 0.8), + 1px 0 0 rgba(0, 0, 0, 0.8), + -1px 0 0 rgba(0, 0, 0, 0.8), + -1px -1px 0 rgba(0, 0, 0, 0.8); +} + +.custom_rickshaw_graph { + position: relative; + left: 40px; +} + +.custom_y_axis { + position: absolute; + width: 40px; + margin-top: -20px; +} + +.custom_slider { + left: 40px; +} + +.custom_x_axis { + position: relative; + left: 40px; + height: 30px; + width: 97%; + top: 20px; + text-align: right; +} + +.chartWrapper { + padding-top: 50px; +} + +/*detail*/ + +.rickshaw_graph .detail { + pointer-events: none; + position: absolute; + top: 0; + z-index: 2; + background: rgba(0, 0, 0, 0.1); + bottom: 0; + width: 1px; + transition: opacity 0.25s linear; + -moz-transition: opacity 0.25s linear; + -o-transition: opacity 0.25s linear; + -webkit-transition: opacity 0.25s linear; +} + +.rickshaw_graph .detail.inactive { + opacity: 0; +} + +.rickshaw_graph .detail .item.active { + opacity: 1; +} + +.rickshaw_graph .detail .x_label { + font-family: Arial, sans-serif; + border-radius: 3px; + padding: 6px; + opacity: 0.5; + border: 1px solid #e0e0e0; + font-size: 12px; + position: absolute; + background: white; + white-space: nowrap; +} + +.rickshaw_graph .detail .x_label.left { + left: 0; +} + +.rickshaw_graph .detail .x_label.right { + right: 0; +} + +.rickshaw_graph .detail .item { + position: absolute; + z-index: 2; + border-radius: 3px; + padding: 0.25em; + font-size: 12px; + font-family: Arial, sans-serif; + opacity: 0; + background: rgba(0, 0, 0, 0.4); + color: white; + border: 1px solid rgba(0, 0, 0, 0.4); + margin-left: 1em; + margin-right: 1em; + margin-top: -1em; + white-space: nowrap; +} + +.rickshaw_graph .detail .item.left { + left: 0; +} + +.rickshaw_graph .detail .item.right { + right: 0; +} + +.rickshaw_graph .detail .item.active { + opacity: 1; + background: rgba(0, 0, 0, 0.8); +} + +.rickshaw_graph .detail .item:after { + position: absolute; + display: block; + width: 0; + height: 0; + + content: ""; + + border: 5px solid transparent; +} + +.rickshaw_graph .detail .item.left:after { + top: 1em; + left: -5px; + margin-top: -5px; + border-right-color: rgba(0, 0, 0, 0.8); + border-left-width: 0; +} + +.rickshaw_graph .detail .item.right:after { + top: 1em; + right: -5px; + margin-top: -5px; + border-left-color: rgba(0, 0, 0, 0.8); + border-right-width: 0; +} + +.rickshaw_graph .detail .dot { + width: 4px; + height: 4px; + margin-left: -3px; + margin-top: -3.5px; + border-radius: 5px; + position: absolute; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); + box-sizing: content-box; + -moz-box-sizing: content-box; + background: white; + border-width: 2px; + border-style: solid; + display: none; + background-clip: padding-box; +} + +.rickshaw_graph .detail .dot.active { + display: block; +} + +/*legend*/ +.rickshaw_legend { + font-family: Arial; + font-size: 12px; + color: white; + background: #404040; + display: inline-block; + padding: 12px 5px; + border-radius: 2px; + position: relative; + float: right; +} + +.rickshaw_legend:hover { + z-index: 10; +} + +.rickshaw_legend .swatch { + width: 10px; + height: 10px; + border: 1px solid rgba(0, 0, 0, 0.2); +} + +.rickshaw_legend .line { + clear: both; + line-height: 140%; + padding-right: 15px; +} + +.rickshaw_legend .line .swatch { + display: inline-block; + margin-right: 3px; + border-radius: 2px; +} + +.rickshaw_legend .label { + margin: 0; + white-space: nowrap; + display: inline; + font-size: inherit; + background-color: transparent; + color: inherit; + font-weight: normal; + line-height: normal; + padding: 0; + text-shadow: none; +} + +.rickshaw_legend .action:hover { + opacity: 0.6; +} + +.rickshaw_legend .action { + margin-right: 0.2em; + opacity: 0.2; + cursor: pointer; + font-size: 14px; +} + +.rickshaw_legend .line.disabled { + opacity: 0.4; +} + +.rickshaw_legend ul { + list-style-type: none; + padding: 0; + margin: 2px; + cursor: pointer; +} + +.rickshaw_legend li { + padding: 0 0 0 2px; + min-width: 80px; + white-space: nowrap; +} + +.rickshaw_legend li:hover { + background: rgba(255, 255, 255, 0.08); + border-radius: 3px; +} + +.rickshaw_legend li:active { + background: rgba(255, 255, 255, 0.2); + border-radius: 3px; +} + +.legend { + display: inline-block; + position: relative; + left: 8px; +} + +.legend_container { + float: right; + padding-right: 10px; + width: 0; + z-index: 1; + position: relative; + opacity: 0.7; +} + +.spaced { + margin-top: 20px !important; +} + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/images/map-marker-1.png b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/images/map-marker-1.png new file mode 100644 index 0000000000000000000000000000000000000000..82ae21a32bbd0a1cee52a59766e7b84e20fea2ad GIT binary patch literal 2824 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 b@ND}(Ny`Cj7IZbQ00000NkvXXu0mjfUyWc` literal 0 HcmV?d00001 diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/d3.min.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/d3.min.js new file mode 100644 index 000000000..71f9715ee --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/d3.min.js @@ -0,0 +1,9488 @@ +/* + * 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() { + var d3 = { + version: "3.5.2" + }; + if (!Date.now) Date.now = function() { + return +new Date(); + }; + var d3_arraySlice = [].slice, d3_array = function(list) { + return d3_arraySlice.call(list); + }; + var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; + try { + d3_array(d3_documentElement.childNodes)[0].nodeType; + } catch (e) { + d3_array = function(list) { + var i = list.length, array = new Array(i); + while (i--) array[i] = list[i]; + return array; + }; + } + try { + d3_document.createElement("div").style.setProperty("opacity", 0, ""); + } catch (error) { + var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; + d3_element_prototype.setAttribute = function(name, value) { + d3_element_setAttribute.call(this, name, value + ""); + }; + d3_element_prototype.setAttributeNS = function(space, local, value) { + d3_element_setAttributeNS.call(this, space, local, value + ""); + }; + d3_style_prototype.setProperty = function(name, value, priority) { + d3_style_setProperty.call(this, name, value + "", priority); + }; + } + d3.ascending = d3_ascending; + function d3_ascending(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + } + d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + }; + d3.min = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n) if ((b = array[i]) != null && b >= b) { + a = b; + break; + } + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { + a = b; + break; + } + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; + } + return a; + }; + d3.max = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n) if ((b = array[i]) != null && b >= b) { + a = b; + break; + } + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { + a = b; + break; + } + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; + } + return a; + }; + d3.extent = function(array, f) { + var i = -1, n = array.length, a, b, c; + if (arguments.length === 1) { + while (++i < n) if ((b = array[i]) != null && b >= b) { + a = c = b; + break; + } + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { + a = c = b; + break; + } + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } + return [ a, c ]; + }; + function d3_number(x) { + return x === null ? NaN : +x; + } + function d3_numeric(x) { + return !isNaN(x); + } + d3.sum = function(array, f) { + var s = 0, n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (d3_numeric(a = +array[i])) s += a; + } else { + while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a; + } + return s; + }; + d3.mean = function(array, f) { + var s = 0, n = array.length, a, i = -1, j = n; + if (arguments.length === 1) { + while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j; + } else { + while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j; + } + if (j) return s / j; + }; + d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; + return e ? v + e * (values[h] - v) : v; + }; + d3.median = function(array, f) { + var numbers = [], n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a); + } else { + while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a); + } + if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5); + }; + d3.variance = function(array, f) { + var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0; + if (arguments.length === 1) { + while (++i < n) { + if (d3_numeric(a = d3_number(array[i]))) { + d = a - m; + m += d / ++j; + s += d * (a - m); + } + } + } else { + while (++i < n) { + if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) { + d = a - m; + m += d / ++j; + s += d * (a - m); + } + } + } + if (j > 1) return s / (j - 1); + }; + d3.deviation = function() { + var v = d3.variance.apply(this, arguments); + return v ? Math.sqrt(v) : v; + }; + function d3_bisector(compare) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1; + } + return lo; + } + }; + } + var d3_bisect = d3_bisector(d3_ascending); + d3.bisectLeft = d3_bisect.left; + d3.bisect = d3.bisectRight = d3_bisect.right; + d3.bisector = function(f) { + return d3_bisector(f.length === 1 ? function(d, x) { + return d3_ascending(f(d), x); + } : f); + }; + d3.shuffle = function(array, i0, i1) { + if ((m = arguments.length) < 3) { + i1 = array.length; + if (m < 2) i0 = 0; + } + var m = i1 - i0, t, i; + while (m) { + i = Math.random() * m-- | 0; + t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t; + } + return array; + }; + d3.permute = function(array, indexes) { + var i = indexes.length, permutes = new Array(i); + while (i--) permutes[i] = array[indexes[i]]; + return permutes; + }; + d3.pairs = function(array) { + var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n); + while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ]; + return pairs; + }; + d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { + zip[j] = arguments[j][i]; + } + } + return zips; + }; + function d3_zipLength(d) { + return d.length; + } + d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); + }; + d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; + }; + d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; + }; + d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({ + key: key, + value: map[key] + }); + return entries; + }; + d3.merge = function(arrays) { + var n = arrays.length, m, i = -1, j = 0, merged, array; + while (++i < n) j += arrays[i].length; + merged = new Array(j); + while (--n >= 0) { + array = arrays[n]; + m = array.length; + while (--m >= 0) { + merged[--j] = array[m]; + } + } + return merged; + }; + var abs = Math.abs; + d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], k = d3_range_integerScale(abs(step)), i = -1, j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; + }; + function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; + } + function d3_class(ctor, properties) { + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } + } + d3.map = function(object, f) { + var map = new d3_Map(); + if (object instanceof d3_Map) { + object.forEach(function(key, value) { + map.set(key, value); + }); + } else if (Array.isArray(object)) { + var i = -1, n = object.length, o; + if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o); + } else { + for (var key in object) map.set(key, object[key]); + } + return map; + }; + function d3_Map() { + this._ = Object.create(null); + } + var d3_map_proto = "__proto__", d3_map_zero = "\x00"; + d3_class(d3_Map, { + has: d3_map_has, + get: function(key) { + return this._[d3_map_escape(key)]; + }, + set: function(key, value) { + return this._[d3_map_escape(key)] = value; + }, + remove: d3_map_remove, + keys: d3_map_keys, + values: function() { + var values = []; + for (var key in this._) values.push(this._[key]); + return values; + }, + entries: function() { + var entries = []; + for (var key in this._) entries.push({ + key: d3_map_unescape(key), + value: this._[key] + }); + return entries; + }, + size: d3_map_size, + empty: d3_map_empty, + forEach: function(f) { + for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]); + } + }); + function d3_map_escape(key) { + return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key; + } + function d3_map_unescape(key) { + return (key += "")[0] === d3_map_zero ? key.slice(1) : key; + } + function d3_map_has(key) { + return d3_map_escape(key) in this._; + } + function d3_map_remove(key) { + return (key = d3_map_escape(key)) in this._ && delete this._[key]; + } + function d3_map_keys() { + var keys = []; + for (var key in this._) keys.push(d3_map_unescape(key)); + return keys; + } + function d3_map_size() { + var size = 0; + for (var key in this._) ++size; + return size; + } + function d3_map_empty() { + for (var key in this._) return false; + return true; + } + d3.nest = function() { + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; + function map(mapType, array, depth) { + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; + var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); + } else { + valuesByKey.set(keyValue, [ object ]); + } + } + if (mapType) { + object = mapType(); + setter = function(keyValue, values) { + object.set(keyValue, map(mapType, values, depth)); + }; + } else { + object = {}; + setter = function(keyValue, values) { + object[keyValue] = map(mapType, values, depth); + }; + } + valuesByKey.forEach(setter); + return object; + } + function entries(map, depth) { + if (depth >= keys.length) return map; + var array = [], sortKey = sortKeys[depth++]; + map.forEach(function(key, keyMap) { + array.push({ + key: key, + values: entries(keyMap, depth) + }); + }); + return sortKey ? array.sort(function(a, b) { + return sortKey(a.key, b.key); + }) : array; + } + nest.map = function(array, mapType) { + return map(mapType, array, 0); + }; + nest.entries = function(array) { + return entries(map(d3.map, array, 0), 0); + }; + nest.key = function(d) { + keys.push(d); + return nest; + }; + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; + }; + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + nest.rollup = function(f) { + rollup = f; + return nest; + }; + return nest; + }; + d3.set = function(array) { + var set = new d3_Set(); + if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); + return set; + }; + function d3_Set() { + this._ = Object.create(null); + } + d3_class(d3_Set, { + has: d3_map_has, + add: function(key) { + this._[d3_map_escape(key += "")] = true; + return key; + }, + remove: d3_map_remove, + values: d3_map_keys, + size: d3_map_size, + empty: d3_map_empty, + forEach: function(f) { + for (var key in this._) f.call(this, d3_map_unescape(key)); + } + }); + d3.behavior = {}; + d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; + }; + function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; + }; + } + function d3_vendorSymbol(object, name) { + if (name in object) return name; + name = name.charAt(0).toUpperCase() + name.slice(1); + for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { + var prefixName = d3_vendorPrefixes[i] + name; + if (prefixName in object) return prefixName; + } + } + var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; + function d3_noop() {} + d3.dispatch = function() { + var dispatch = new d3_dispatch(), i = -1, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; + }; + function d3_dispatch() {} + d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), name = ""; + if (i >= 0) { + name = type.slice(i + 1); + type = type.slice(0, i); + } + if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); + if (arguments.length === 2) { + if (listener == null) for (type in this) { + if (this.hasOwnProperty(type)) this[type].on(name, null); + } + return this; + } + }; + function d3_dispatch_event(dispatch) { + var listeners = [], listenerByName = new d3_Map(); + function event() { + var z = listeners, i = -1, n = z.length, l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + event.on = function(name, listener) { + var l = listenerByName.get(name), i; + if (arguments.length < 2) return l && l.on; + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + if (listener) listeners.push(listenerByName.set(name, { + on: listener + })); + return dispatch; + }; + return event; + } + d3.event = null; + function d3_eventPreventDefault() { + d3.event.preventDefault(); + } + function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; + } + function d3_eventDispatch(target) { + var dispatch = new d3_dispatch(), i = 0, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + dispatch.of = function(thiz, argumentz) { + return function(e1) { + try { + var e0 = e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); + } finally { + d3.event = e0; + } + }; + }; + return dispatch; + } + d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); + }; + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + var d3_subclass = {}.__proto__ ? function(object, prototype) { + object.__proto__ = prototype; + } : function(object, prototype) { + for (var property in prototype) object[property] = prototype[property]; + }; + function d3_selection(groups) { + d3_subclass(groups, d3_selectionPrototype); + return groups; + } + var d3_select = function(s, n) { + return n.querySelector(s); + }, d3_selectAll = function(s, n) { + return n.querySelectorAll(s); + }, d3_selectMatcher = d3_documentElement.matches || d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { + return d3_selectMatcher.call(n, s); + }; + if (typeof Sizzle === "function") { + d3_select = function(s, n) { + return Sizzle(s, n)[0] || null; + }; + d3_selectAll = Sizzle; + d3_selectMatches = Sizzle.matchesSelector; + } + d3.selection = function() { + return d3_selectionRoot; + }; + var d3_selectionPrototype = d3.selection.prototype = []; + d3_selectionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, group, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i, j)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selector(selector) { + return typeof selector === "function" ? selector : function() { + return d3_select(selector, this); + }; + } + d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, node; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); + subgroup.parentNode = node; + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selectorAll(selector) { + return typeof selector === "function" ? selector : function() { + return d3_selectAll(selector, this); + }; + } + var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), prefix = name; + if (i >= 0) { + prefix = name.slice(0, i); + name = name.slice(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) ? { + space: d3_nsPrefix[prefix], + local: name + } : name; + } + }; + d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); + } + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + return this.each(d3_selection_attr(name, value)); + }; + function d3_selection_attr(name, value) { + name = d3.ns.qualify(name); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); + } + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; + } + function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); + } + d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.getAttribute("class"); + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + return this.each(d3_selection_classed(name, value)); + }; + function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); + } + function d3_selection_classes(name) { + return (name + "").trim().split(/^|\s+/); + } + function d3_selection_classed(name, value) { + name = d3_selection_classes(name).map(d3_selection_classedName); + var n = name.length; + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + return typeof value === "function" ? classedFunction : classedConstant; + } + function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.getAttribute("class") || ""; + if (value) { + re.lastIndex = 0; + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); + } else { + node.setAttribute("class", d3_collapse(c.replace(re, " "))); + } + }; + } + d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; + } + if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); + priority = ""; + } + return this.each(d3_selection_style(name, value, priority)); + }; + function d3_selection_style(name, value, priority) { + function styleNull() { + this.style.removeProperty(name); + } + function styleConstant() { + this.style.setProperty(name, value, priority); + } + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); + } + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; + } + d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") return this.node()[name]; + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; + } + return this.each(d3_selection_property(name, value)); + }; + function d3_selection_property(name, value) { + function propertyNull() { + delete this[name]; + } + function propertyConstant() { + this[name] = value; + } + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; else this[name] = x; + } + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; + } + d3_selectionPrototype.text = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + } : value == null ? function() { + this.textContent = ""; + } : function() { + this.textContent = value; + }) : this.node().textContent; + }; + d3_selectionPrototype.html = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + } : value == null ? function() { + this.innerHTML = ""; + } : function() { + this.innerHTML = value; + }) : this.node().innerHTML; + }; + d3_selectionPrototype.append = function(name) { + name = d3_selection_creator(name); + return this.select(function() { + return this.appendChild(name.apply(this, arguments)); + }); + }; + function d3_selection_creator(name) { + return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { + return this.ownerDocument.createElementNS(name.space, name.local); + } : function() { + return this.ownerDocument.createElementNS(this.namespaceURI, name); + }; + } + d3_selectionPrototype.insert = function(name, before) { + name = d3_selection_creator(name); + before = d3_selection_selector(before); + return this.select(function() { + return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null); + }); + }; + d3_selectionPrototype.remove = function() { + return this.each(d3_selectionRemove); + }; + function d3_selectionRemove() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + } + d3_selectionPrototype.data = function(value, key) { + var i = -1, n = this.length, group, node; + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } + } + return value; + } + function bind(group, groupData) { + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; + if (key) { + var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue; + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.has(keyValue = key.call(node = group[i], node.__data__, i))) { + exitNodes[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues[i] = keyValue; + } + for (i = -1; ++i < m; ) { + if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) { + enterNodes[i] = d3_selection_dataNode(nodeData); + } else if (node !== true) { + updateNodes[i] = node; + node.__data__ = nodeData; + } + nodeByKeyValue.set(keyValue, true); + } + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.get(keyValues[i]) !== true) { + exitNodes[i] = group[i]; + } + } + } else { + for (i = -1; ++i < n0; ) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + } + for (;i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + } + for (;i < n; ++i) { + exitNodes[i] = group[i]; + } + } + enterNodes.update = updateNodes; + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); + } + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); + } + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + update.enter = function() { + return enter; + }; + update.exit = function() { + return exit; + }; + return update; + }; + function d3_selection_dataNode(data) { + return { + __data__: data + }; + } + d3_selectionPrototype.datum = function(value) { + return arguments.length ? this.property("__data__", value) : this.property("__data__"); + }; + d3_selectionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { + subgroup.push(node); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); + }; + } + d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; + }; + d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); + return this.order(); + }; + function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3_ascending; + return function(a, b) { + return a && b ? comparator(a.__data__, b.__data__) : !a - !b; + }; + } + d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); + }; + function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } + } + return groups; + } + d3_selectionPrototype.call = function(callback) { + var args = d3_array(arguments); + callback.apply(args[0] = this, args); + return this; + }; + d3_selectionPrototype.empty = function() { + return !this.node(); + }; + d3_selectionPrototype.node = function() { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } + } + return null; + }; + d3_selectionPrototype.size = function() { + var n = 0; + d3_selection_each(this, function() { + ++n; + }); + return n; + }; + function d3_selection_enter(selection) { + d3_subclass(selection, d3_selection_enterPrototype); + return selection; + } + var d3_selection_enterPrototype = []; + d3.selection.enter = d3_selection_enter; + d3.selection.enter.prototype = d3_selection_enterPrototype; + d3_selection_enterPrototype.append = d3_selectionPrototype.append; + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; + d3_selection_enterPrototype.node = d3_selectionPrototype.node; + d3_selection_enterPrototype.call = d3_selectionPrototype.call; + d3_selection_enterPrototype.size = d3_selectionPrototype.size; + d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, upgroup, group, node; + for (var j = -1, m = this.length; ++j < m; ) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); + subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + d3_selection_enterPrototype.insert = function(name, before) { + if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); + return d3_selectionPrototype.insert.call(this, name, before); + }; + function d3_selection_enterInsertBefore(enter) { + var i0, j0; + return function(d, i, j) { + var group = enter[j].update, n = group.length, node; + if (j != j0) j0 = j, i0 = 0; + if (i >= i0) i0 = i + 1; + while (!(node = group[i0]) && ++i0 < n) ; + return node; + }; + } + d3.select = function(node) { + var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + d3.selectAll = function(nodes) { + var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + var d3_selectionRoot = d3.select(d3_documentElement); + d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + if (n < 2) return (n = this.node()["__on" + type]) && n._; + capture = false; + } + return this.each(d3_selection_on(type, listener, capture)); + }; + function d3_selection_on(type, listener, capture) { + var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; + if (i > 0) type = type.slice(0, i); + var filter = d3_selection_onFilters.get(type); + if (filter) type = filter, wrap = d3_selection_onFilter; + function onRemove() { + var l = this[name]; + if (l) { + this.removeEventListener(type, l, l.$); + delete this[name]; + } + } + function onAdd() { + var l = wrap(listener, d3_array(arguments)); + onRemove.call(this); + this.addEventListener(type, this[name] = l, l.$ = capture); + l._ = listener; + } + function removeAll() { + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; + for (var name in this) { + if (match = name.match(re)) { + var l = this[name]; + this.removeEventListener(match[1], l, l.$); + delete this[name]; + } + } + } + return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; + } + var d3_selection_onFilters = d3.map({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }); + d3_selection_onFilters.forEach(function(k) { + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); + }); + function d3_selection_onListener(listener, argumentz) { + return function(e) { + var o = d3.event; + d3.event = e; + argumentz[0] = this.__data__; + try { + listener.apply(this, argumentz); + } finally { + d3.event = o; + } + }; + } + function d3_selection_onFilter(listener, argumentz) { + var l = d3_selection_onListener(listener, argumentz); + return function(e) { + var target = this, related = e.relatedTarget; + if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { + l.call(target, e); + } + }; + } + var d3_event_dragSelect = "onselectstart" in d3_document ? null : d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; + function d3_event_dragSuppress() { + var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault); + if (d3_event_dragSelect) { + var style = d3_documentElement.style, select = style[d3_event_dragSelect]; + style[d3_event_dragSelect] = "none"; + } + return function(suppressClick) { + w.on(name, null); + if (d3_event_dragSelect) style[d3_event_dragSelect] = select; + if (suppressClick) { + var off = function() { + w.on(click, null); + }; + w.on(click, function() { + d3_eventPreventDefault(); + off(); + }, true); + setTimeout(off, 0); + } + }; + } + d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); + }; + var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; + function d3_mousePoint(container, e) { + if (e.changedTouches) e = e.changedTouches[0]; + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { + svg = d3.select("body").append("svg").style({ + position: "absolute", + top: 0, + left: 0, + margin: 0, + padding: 0, + border: "none" + }, "important"); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); + } + if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX, + point.y = e.clientY; + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [ point.x, point.y ]; + } + var rect = container.getBoundingClientRect(); + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; + } + d3.touch = function(container, touches, identifier) { + if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches; + if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) { + if ((touch = touches[i]).identifier === identifier) { + return d3_mousePoint(container, touch); + } + } + }; + d3.behavior.drag = function() { + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_behavior_dragMouseSubject, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_behavior_dragTouchSubject, "touchmove", "touchend"); + function drag() { + this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); + } + function dragstart(id, position, subject, move, end) { + return function() { + var that = this, target = d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject()).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(), position0 = position(parent, dragId); + if (origin) { + dragOffset = origin.apply(that, arguments); + dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ]; + } else { + dragOffset = [ 0, 0 ]; + } + dispatch({ + type: "dragstart" + }); + function moved() { + var position1 = position(parent, dragId), dx, dy; + if (!position1) return; + dx = position1[0] - position0[0]; + dy = position1[1] - position0[1]; + dragged |= dx | dy; + position0 = position1; + dispatch({ + type: "drag", + x: position1[0] + dragOffset[0], + y: position1[1] + dragOffset[1], + dx: dx, + dy: dy + }); + } + function ended() { + if (!position(parent, dragId)) return; + dragSubject.on(move + dragName, null).on(end + dragName, null); + dragRestore(dragged && d3.event.target === target); + dispatch({ + type: "dragend" + }); + } + }; + } + drag.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return drag; + }; + return d3.rebind(drag, event, "on"); + }; + function d3_behavior_dragTouchId() { + return d3.event.changedTouches[0].identifier; + } + function d3_behavior_dragTouchSubject() { + return d3.event.target; + } + function d3_behavior_dragMouseSubject() { + return d3_window; + } + d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; + }; + var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π; + function d3_sgn(x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } + function d3_cross2d(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); + } + function d3_acos(x) { + return x > 1 ? 0 : x < -1 ? π : Math.acos(x); + } + function d3_asin(x) { + return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x); + } + function d3_sinh(x) { + return ((x = Math.exp(x)) - 1 / x) / 2; + } + function d3_cosh(x) { + return ((x = Math.exp(x)) + 1 / x) / 2; + } + function d3_tanh(x) { + return ((x = Math.exp(2 * x)) - 1) / (x + 1); + } + function d3_haversin(x) { + return (x = Math.sin(x / 2)) * x; + } + var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4; + d3.interpolateZoom = function(p0, p1) { + var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2]; + var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ; + function interpolate(t) { + var s = t * S; + if (dr) { + var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); + return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ]; + } + return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ]; + } + interpolate.duration = S * 1e3; + return interpolate; + }; + d3.behavior.zoom = function() { + var view = { + x: 0, + y: 0, + k: 1 + }, translate0, center0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, duration = 250, zooming = 0, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1; + function zoom(g) { + g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); + } + zoom.event = function(g) { + g.each(function() { + var dispatch = event.of(this, arguments), view1 = view; + if (d3_transitionInheritId) { + d3.select(this).transition().each("start.zoom", function() { + view = this.__chart__ || { + x: 0, + y: 0, + k: 1 + }; + zoomstarted(dispatch); + }).tween("zoom:zoom", function() { + var dx = size[0], dy = size[1], cx = center0 ? center0[0] : dx / 2, cy = center0 ? center0[1] : dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]); + return function(t) { + var l = i(t), k = dx / l[2]; + this.__chart__ = view = { + x: cx - l[0] * k, + y: cy - l[1] * k, + k: k + }; + zoomed(dispatch); + }; + }).each("interrupt.zoom", function() { + zoomended(dispatch); + }).each("end.zoom", function() { + zoomended(dispatch); + }); + } else { + this.__chart__ = view; + zoomstarted(dispatch); + zoomed(dispatch); + zoomended(dispatch); + } + }); + }; + zoom.translate = function(_) { + if (!arguments.length) return [ view.x, view.y ]; + view = { + x: +_[0], + y: +_[1], + k: view.k + }; + rescale(); + return zoom; + }; + zoom.scale = function(_) { + if (!arguments.length) return view.k; + view = { + x: view.x, + y: view.y, + k: +_ + }; + rescale(); + return zoom; + }; + zoom.scaleExtent = function(_) { + if (!arguments.length) return scaleExtent; + scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ]; + return zoom; + }; + zoom.center = function(_) { + if (!arguments.length) return center; + center = _ && [ +_[0], +_[1] ]; + return zoom; + }; + zoom.size = function(_) { + if (!arguments.length) return size; + size = _ && [ +_[0], +_[1] ]; + return zoom; + }; + zoom.duration = function(_) { + if (!arguments.length) return duration; + duration = +_; + return zoom; + }; + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + view = { + x: 0, + y: 0, + k: 1 + }; + return zoom; + }; + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + view = { + x: 0, + y: 0, + k: 1 + }; + return zoom; + }; + function location(p) { + return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ]; + } + function point(l) { + return [ l[0] * view.k + view.x, l[1] * view.k + view.y ]; + } + function scaleTo(s) { + view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + function translateTo(p, l) { + l = point(l); + view.x += p[0] - l[0]; + view.y += p[1] - l[1]; + } + function zoomTo(that, p, l, k) { + that.__chart__ = { + x: view.x, + y: view.y, + k: view.k + }; + scaleTo(Math.pow(2, k)); + translateTo(center0 = p, l); + that = d3.select(that); + if (duration > 0) that = that.transition().duration(duration); + that.call(zoom.event); + } + function rescale() { + if (x1) x1.domain(x0.range().map(function(x) { + return (x - view.x) / view.k; + }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { + return (y - view.y) / view.k; + }).map(y0.invert)); + } + function zoomstarted(dispatch) { + if (!zooming++) dispatch({ + type: "zoomstart" + }); + } + function zoomed(dispatch) { + rescale(); + dispatch({ + type: "zoom", + scale: view.k, + translate: [ view.x, view.y ] + }); + } + function zoomended(dispatch) { + if (!--zooming) dispatch({ + type: "zoomend" + }); + center0 = null; + } + function mousedowned() { + var that = this, target = d3.event.target, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(); + d3_selection_interrupt.call(that); + zoomstarted(dispatch); + function moved() { + dragged = 1; + translateTo(d3.mouse(that), location0); + zoomed(dispatch); + } + function ended() { + subject.on(mousemove, null).on(mouseup, null); + dragRestore(dragged && d3.event.target === target); + zoomended(dispatch); + } + } + function touchstarted() { + var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, targets = [], subject = d3.select(that), dragRestore = d3_event_dragSuppress(); + started(); + zoomstarted(dispatch); + subject.on(mousedown, null).on(touchstart, started); + function relocate() { + var touches = d3.touches(that); + scale0 = view.k; + touches.forEach(function(t) { + if (t.identifier in locations0) locations0[t.identifier] = location(t); + }); + return touches; + } + function started() { + var target = d3.event.target; + d3.select(target).on(touchmove, moved).on(touchend, ended); + targets.push(target); + var changed = d3.event.changedTouches; + for (var i = 0, n = changed.length; i < n; ++i) { + locations0[changed[i].identifier] = null; + } + var touches = relocate(), now = Date.now(); + if (touches.length === 1) { + if (now - touchtime < 500) { + var p = touches[0]; + zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1); + d3_eventPreventDefault(); + } + touchtime = now; + } else if (touches.length > 1) { + var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; + distance0 = dx * dx + dy * dy; + } + } + function moved() { + var touches = d3.touches(that), p0, l0, p1, l1; + d3_selection_interrupt.call(that); + for (var i = 0, n = touches.length; i < n; ++i, l1 = null) { + p1 = touches[i]; + if (l1 = locations0[p1.identifier]) { + if (l0) break; + p0 = p1, l0 = l1; + } + } + if (l1) { + var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0); + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; + scaleTo(scale1 * scale0); + } + touchtime = null; + translateTo(p0, l0); + zoomed(dispatch); + } + function ended() { + if (d3.event.touches.length) { + var changed = d3.event.changedTouches; + for (var i = 0, n = changed.length; i < n; ++i) { + delete locations0[changed[i].identifier]; + } + for (var identifier in locations0) { + return void relocate(); + } + } + d3.selectAll(targets).on(zoomName, null); + subject.on(mousedown, mousedowned).on(touchstart, touchstarted); + dragRestore(); + zoomended(dispatch); + } + } + function mousewheeled() { + var dispatch = event.of(this, arguments); + if (mousewheelTimer) clearTimeout(mousewheelTimer); else translate0 = location(center0 = center || d3.mouse(this)), + d3_selection_interrupt.call(this), zoomstarted(dispatch); + mousewheelTimer = setTimeout(function() { + mousewheelTimer = null; + zoomended(dispatch); + }, 50); + d3_eventPreventDefault(); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k); + translateTo(center0, translate0); + zoomed(dispatch); + } + function dblclicked() { + var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2; + zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1); + } + return d3.rebind(zoom, event, "on"); + }; + var d3_behavior_zoomInfinity = [ 0, Infinity ]; + var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); + }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return d3.event.wheelDelta; + }, "mousewheel") : (d3_behavior_zoomDelta = function() { + return -d3.event.detail; + }, "MozMousePixelScroll"); + d3.color = d3_color; + function d3_color() {} + d3_color.prototype.toString = function() { + return this.rgb() + ""; + }; + d3.hsl = d3_hsl; + function d3_hsl(h, s, l) { + return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) : arguments.length < 2 ? h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : new d3_hsl(h, s, l); + } + var d3_hslPrototype = d3_hsl.prototype = new d3_color(); + d3_hslPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return new d3_hsl(this.h, this.s, this.l / k); + }; + d3_hslPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return new d3_hsl(this.h, this.s, k * this.l); + }; + d3_hslPrototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); + }; + function d3_hsl_rgb(h, s, l) { + var m1, m2; + h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; + s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + function v(h) { + if (h > 360) h -= 360; else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + function vv(h) { + return Math.round(v(h) * 255); + } + return new d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + } + d3.hcl = d3_hcl; + function d3_hcl(h, c, l) { + return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) : arguments.length < 2 ? h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l) : h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : new d3_hcl(h, c, l); + } + var d3_hclPrototype = d3_hcl.prototype = new d3_color(); + d3_hclPrototype.brighter = function(k) { + return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.darker = function(k) { + return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); + }; + function d3_hcl_lab(h, c, l) { + if (isNaN(h)) h = 0; + if (isNaN(c)) c = 0; + return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); + } + d3.lab = d3_lab; + function d3_lab(l, a, b) { + return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) : arguments.length < 2 ? l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) : l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b) : new d3_lab(l, a, b); + } + var d3_lab_K = 18; + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; + var d3_labPrototype = d3_lab.prototype = new d3_color(); + d3_labPrototype.brighter = function(k) { + return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.darker = function(k) { + return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); + }; + function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return new d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); + } + function d3_lab_hcl(l, a, b) { + return l > 0 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : new d3_hcl(NaN, NaN, l); + } + function d3_lab_xyz(x) { + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; + } + function d3_xyz_lab(x) { + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; + } + function d3_xyz_rgb(r) { + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); + } + d3.rgb = d3_rgb; + function d3_rgb(r, g, b) { + return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) : arguments.length < 2 ? r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : new d3_rgb(r, g, b); + } + function d3_rgbNumber(value) { + return new d3_rgb(value >> 16, value >> 8 & 255, value & 255); + } + function d3_rgbString(value) { + return d3_rgbNumber(value) + ""; + } + var d3_rgbPrototype = d3_rgb.prototype = new d3_color(); + d3_rgbPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + var r = this.r, g = this.g, b = this.b, i = 30; + if (!r && !g && !b) return new d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k)); + }; + d3_rgbPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return new d3_rgb(k * this.r, k * this.g, k * this.b); + }; + d3_rgbPrototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); + }; + d3_rgbPrototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); + }; + function d3_rgb_hex(v) { + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); + } + function d3_rgb_parse(format, rgb, hsl) { + var r = 0, g = 0, b = 0, m1, m2, color; + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": + { + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); + } + + case "rgb": + { + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); + } + } + } + if (color = d3_rgb_names.get(format)) return rgb(color.r, color.g, color.b); + if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) { + if (format.length === 4) { + r = (color & 3840) >> 4; + r = r >> 4 | r; + g = color & 240; + g = g >> 4 | g; + b = color & 15; + b = b << 4 | b; + } else if (format.length === 7) { + r = (color & 16711680) >> 16; + g = (color & 65280) >> 8; + b = color & 255; + } + } + return rgb(r, g, b); + } + function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; + h *= 60; + } else { + h = NaN; + s = l > 0 && l < 1 ? 0 : h; + } + return new d3_hsl(h, s, l); + } + function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + } + function d3_rgb_xyz(r) { + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + } + function d3_rgb_parseNumber(c) { + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + } + var d3_rgb_names = d3.map({ + aliceblue: 15792383, + antiquewhite: 16444375, + aqua: 65535, + aquamarine: 8388564, + azure: 15794175, + beige: 16119260, + bisque: 16770244, + black: 0, + blanchedalmond: 16772045, + blue: 255, + blueviolet: 9055202, + brown: 10824234, + burlywood: 14596231, + cadetblue: 6266528, + chartreuse: 8388352, + chocolate: 13789470, + coral: 16744272, + cornflowerblue: 6591981, + cornsilk: 16775388, + crimson: 14423100, + cyan: 65535, + darkblue: 139, + darkcyan: 35723, + darkgoldenrod: 12092939, + darkgray: 11119017, + darkgreen: 25600, + darkgrey: 11119017, + darkkhaki: 12433259, + darkmagenta: 9109643, + darkolivegreen: 5597999, + darkorange: 16747520, + darkorchid: 10040012, + darkred: 9109504, + darksalmon: 15308410, + darkseagreen: 9419919, + darkslateblue: 4734347, + darkslategray: 3100495, + darkslategrey: 3100495, + darkturquoise: 52945, + darkviolet: 9699539, + deeppink: 16716947, + deepskyblue: 49151, + dimgray: 6908265, + dimgrey: 6908265, + dodgerblue: 2003199, + firebrick: 11674146, + floralwhite: 16775920, + forestgreen: 2263842, + fuchsia: 16711935, + gainsboro: 14474460, + ghostwhite: 16316671, + gold: 16766720, + goldenrod: 14329120, + gray: 8421504, + green: 32768, + greenyellow: 11403055, + grey: 8421504, + honeydew: 15794160, + hotpink: 16738740, + indianred: 13458524, + indigo: 4915330, + ivory: 16777200, + khaki: 15787660, + lavender: 15132410, + lavenderblush: 16773365, + lawngreen: 8190976, + lemonchiffon: 16775885, + lightblue: 11393254, + lightcoral: 15761536, + lightcyan: 14745599, + lightgoldenrodyellow: 16448210, + lightgray: 13882323, + lightgreen: 9498256, + lightgrey: 13882323, + lightpink: 16758465, + lightsalmon: 16752762, + lightseagreen: 2142890, + lightskyblue: 8900346, + lightslategray: 7833753, + lightslategrey: 7833753, + lightsteelblue: 11584734, + lightyellow: 16777184, + lime: 65280, + limegreen: 3329330, + linen: 16445670, + magenta: 16711935, + maroon: 8388608, + mediumaquamarine: 6737322, + mediumblue: 205, + mediumorchid: 12211667, + mediumpurple: 9662683, + mediumseagreen: 3978097, + mediumslateblue: 8087790, + mediumspringgreen: 64154, + mediumturquoise: 4772300, + mediumvioletred: 13047173, + midnightblue: 1644912, + mintcream: 16121850, + mistyrose: 16770273, + moccasin: 16770229, + navajowhite: 16768685, + navy: 128, + oldlace: 16643558, + olive: 8421376, + olivedrab: 7048739, + orange: 16753920, + orangered: 16729344, + orchid: 14315734, + palegoldenrod: 15657130, + palegreen: 10025880, + paleturquoise: 11529966, + palevioletred: 14381203, + papayawhip: 16773077, + peachpuff: 16767673, + peru: 13468991, + pink: 16761035, + plum: 14524637, + powderblue: 11591910, + purple: 8388736, + red: 16711680, + rosybrown: 12357519, + royalblue: 4286945, + saddlebrown: 9127187, + salmon: 16416882, + sandybrown: 16032864, + seagreen: 3050327, + seashell: 16774638, + sienna: 10506797, + silver: 12632256, + skyblue: 8900331, + slateblue: 6970061, + slategray: 7372944, + slategrey: 7372944, + snow: 16775930, + springgreen: 65407, + steelblue: 4620980, + tan: 13808780, + teal: 32896, + thistle: 14204888, + tomato: 16737095, + turquoise: 4251856, + violet: 15631086, + wheat: 16113331, + white: 16777215, + whitesmoke: 16119285, + yellow: 16776960, + yellowgreen: 10145074 + }); + d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgbNumber(value)); + }); + function d3_functor(v) { + return typeof v === "function" ? v : function() { + return v; + }; + } + d3.functor = d3_functor; + function d3_identity(d) { + return d; + } + d3.xhr = d3_xhrType(d3_identity); + function d3_xhrType(response) { + return function(url, mimeType, callback) { + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, + mimeType = null; + return d3_xhr(url, mimeType, response, callback); + }; + } + function d3_xhr(url, mimeType, response, callback) { + var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; + if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); + "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { + request.readyState > 3 && respond(); + }; + function respond() { + var status = request.status, result; + if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) { + try { + result = response.call(xhr, request); + } catch (e) { + dispatch.error.call(xhr, e); + return; + } + dispatch.load.call(xhr, result); + } else { + dispatch.error.call(xhr, request); + } + } + request.onprogress = function(event) { + var o = d3.event; + d3.event = event; + try { + dispatch.progress.call(xhr, request); + } finally { + d3.event = o; + } + }; + xhr.header = function(name, value) { + name = (name + "").toLowerCase(); + if (arguments.length < 2) return headers[name]; + if (value == null) delete headers[name]; else headers[name] = value + ""; + return xhr; + }; + xhr.mimeType = function(value) { + if (!arguments.length) return mimeType; + mimeType = value == null ? null : value + ""; + return xhr; + }; + xhr.responseType = function(value) { + if (!arguments.length) return responseType; + responseType = value; + return xhr; + }; + xhr.response = function(value) { + response = value; + return xhr; + }; + [ "get", "post" ].forEach(function(method) { + xhr[method] = function() { + return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); + }; + }); + xhr.send = function(method, data, callback) { + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; + request.open(method, url, true); + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); + if (responseType != null) request.responseType = responseType; + if (callback != null) xhr.on("error", callback).on("load", function(request) { + callback(null, request); + }); + dispatch.beforesend.call(xhr, request); + request.send(data == null ? null : data); + return xhr; + }; + xhr.abort = function() { + request.abort(); + return xhr; + }; + d3.rebind(xhr, dispatch, "on"); + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); + } + function d3_xhr_fixCallback(callback) { + return callback.length === 1 ? function(error, request) { + callback(error == null ? request : null); + } : callback; + } + function d3_xhrHasResponse(request) { + var type = request.responseType; + return type && type !== "text" ? request.response : request.responseText; + } + d3.dsv = function(delimiter, mimeType) { + var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); + function dsv(url, row, callback) { + if (arguments.length < 3) callback = row, row = null; + var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback); + xhr.row = function(_) { + return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; + }; + return xhr; + } + function response(request) { + return dsv.parse(request.responseText); + } + function typedResponse(f) { + return function(request) { + return dsv.parse(request.responseText, f); + }; + } + dsv.parse = function(text, f) { + var o; + return dsv.parseRows(text, function(row, i) { + if (o) return o(row, i - 1); + var a = new Function("d", "return {" + row.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "]"; + }).join(",") + "}"); + o = f ? function(row, i) { + return f(a(row), i); + } : a; + }); + }; + dsv.parseRows = function(text, f) { + var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; + function token() { + if (I >= N) return EOF; + if (eol) return eol = false, EOL; + var j = I; + if (text.charCodeAt(j) === 34) { + var i = j; + while (i++ < N) { + if (text.charCodeAt(i) === 34) { + if (text.charCodeAt(i + 1) !== 34) break; + ++i; + } + } + I = i + 2; + var c = text.charCodeAt(i + 1); + if (c === 13) { + eol = true; + if (text.charCodeAt(i + 2) === 10) ++I; + } else if (c === 10) { + eol = true; + } + return text.slice(j + 1, i).replace(/""/g, '"'); + } + while (I < N) { + var c = text.charCodeAt(I++), k = 1; + if (c === 10) eol = true; else if (c === 13) { + eol = true; + if (text.charCodeAt(I) === 10) ++I, ++k; + } else if (c !== delimiterCode) continue; + return text.slice(j, I - k); + } + return text.slice(j); + } + while ((t = token()) !== EOF) { + var a = []; + while (t !== EOL && t !== EOF) { + a.push(t); + t = token(); + } + if (f && (a = f(a, n++)) == null) continue; + rows.push(a); + } + return rows; + }; + dsv.format = function(rows) { + if (Array.isArray(rows[0])) return dsv.formatRows(rows); + var fieldSet = new d3_Set(), fields = []; + rows.forEach(function(row) { + for (var field in row) { + if (!fieldSet.has(field)) { + fields.push(fieldSet.add(field)); + } + } + }); + return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { + return fields.map(function(field) { + return formatValue(row[field]); + }).join(delimiter); + })).join("\n"); + }; + dsv.formatRows = function(rows) { + return rows.map(formatRow).join("\n"); + }; + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + function formatValue(text) { + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; + } + return dsv; + }; + d3.csv = d3.dsv(",", "text/csv"); + d3.tsv = d3.dsv(" ", "text/tab-separated-values"); + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { + setTimeout(callback, 17); + }; + d3.timer = function(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + var time = then + delay, timer = { + c: callback, + t: time, + f: false, + n: null + }; + if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer; + d3_timer_queueTail = timer; + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + }; + function d3_timer_step() { + var now = d3_timer_mark(), delay = d3_timer_sweep() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); + } + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + } + d3.timer.flush = function() { + d3_timer_mark(); + d3_timer_sweep(); + }; + function d3_timer_mark() { + var now = Date.now(); + d3_timer_active = d3_timer_queueHead; + while (d3_timer_active) { + if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t); + d3_timer_active = d3_timer_active.n; + } + return now; + } + function d3_timer_sweep() { + var t0, t1 = d3_timer_queueHead, time = Infinity; + while (t1) { + if (t1.f) { + t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n; + } else { + if (t1.t < time) time = t1.t; + t1 = (t0 = t1).n; + } + } + d3_timer_queueTail = t0; + return time; + } + function d3_format_precision(x, p) { + return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); + } + d3.round = function(x, n) { + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); + }; + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); + d3.formatPrefix = function(value, precision) { + var i = 0; + if (value) { + if (value < 0) value *= -1; + if (precision) value = d3.round(value, d3_format_precision(value, precision)); + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); + i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3)); + } + return d3_formatPrefixes[8 + i / 3]; + }; + function d3_formatPrefix(d, i) { + var k = Math.pow(10, abs(8 - i) * 3); + return { + scale: i > 8 ? function(d) { + return d / k; + } : function(d) { + return d * k; + }, + symbol: d + }; + } + function d3_locale_numberFormat(locale) { + var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping && locale_thousands ? function(value, width) { + var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0; + while (i > 0 && g > 0) { + if (length + g + 1 > width) g = Math.max(1, width - length); + t.push(value.substring(i -= g, i + g)); + if ((length += g + 1) > width) break; + g = locale_grouping[j = (j + 1) % locale_grouping.length]; + } + return t.reverse().join(locale_thousands); + } : d3_identity; + return function(specifier) { + var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false, exponent = true; + if (precision) precision = +precision.substring(1); + if (zfill || fill === "0" && align === "=") { + zfill = fill = "0"; + align = "="; + } + switch (type) { + case "n": + comma = true; + type = "g"; + break; + + case "%": + scale = 100; + suffix = "%"; + type = "f"; + break; + + case "p": + scale = 100; + suffix = "%"; + type = "r"; + break; + + case "b": + case "o": + case "x": + case "X": + if (symbol === "#") prefix = "0" + type.toLowerCase(); + + case "c": + exponent = false; + + case "d": + integer = true; + precision = 0; + break; + + case "s": + scale = -1; + type = "r"; + break; + } + if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1]; + if (type == "r" && !precision) type = "g"; + if (precision != null) { + if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); + } + type = d3_format_types.get(type) || d3_format_typeDefault; + var zcomma = zfill && comma; + return function(value) { + var fullSuffix = suffix; + if (integer && value % 1) return ""; + var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign; + if (scale < 0) { + var unit = d3.formatPrefix(value, precision); + value = unit.scale(value); + fullSuffix = unit.symbol + suffix; + } else { + value *= scale; + } + value = type(value, precision); + var i = value.lastIndexOf("."), before, after; + if (i < 0) { + var j = exponent ? value.lastIndexOf("e") : -1; + if (j < 0) before = value, after = ""; else before = value.substring(0, j), after = value.substring(j); + } else { + before = value.substring(0, i); + after = locale_decimal + value.substring(i + 1); + } + if (!zfill && comma) before = formatGroup(before, Infinity); + var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; + if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity); + negative += prefix; + value = before + after; + return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix; + }; + }; + } + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; + var d3_format_types = d3.map({ + b: function(x) { + return x.toString(2); + }, + c: function(x) { + return String.fromCharCode(x); + }, + o: function(x) { + return x.toString(8); + }, + x: function(x) { + return x.toString(16); + }, + X: function(x) { + return x.toString(16).toUpperCase(); + }, + g: function(x, p) { + return x.toPrecision(p); + }, + e: function(x, p) { + return x.toExponential(p); + }, + f: function(x, p) { + return x.toFixed(p); + }, + r: function(x, p) { + return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); + } + }); + function d3_format_typeDefault(x) { + return x + ""; + } + var d3_time = d3.time = {}, d3_date = Date; + function d3_date_utc() { + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); + } + d3_date_utc.prototype = { + getDate: function() { + return this._.getUTCDate(); + }, + getDay: function() { + return this._.getUTCDay(); + }, + getFullYear: function() { + return this._.getUTCFullYear(); + }, + getHours: function() { + return this._.getUTCHours(); + }, + getMilliseconds: function() { + return this._.getUTCMilliseconds(); + }, + getMinutes: function() { + return this._.getUTCMinutes(); + }, + getMonth: function() { + return this._.getUTCMonth(); + }, + getSeconds: function() { + return this._.getUTCSeconds(); + }, + getTime: function() { + return this._.getTime(); + }, + getTimezoneOffset: function() { + return 0; + }, + valueOf: function() { + return this._.valueOf(); + }, + setDate: function() { + d3_time_prototype.setUTCDate.apply(this._, arguments); + }, + setDay: function() { + d3_time_prototype.setUTCDay.apply(this._, arguments); + }, + setFullYear: function() { + d3_time_prototype.setUTCFullYear.apply(this._, arguments); + }, + setHours: function() { + d3_time_prototype.setUTCHours.apply(this._, arguments); + }, + setMilliseconds: function() { + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); + }, + setMinutes: function() { + d3_time_prototype.setUTCMinutes.apply(this._, arguments); + }, + setMonth: function() { + d3_time_prototype.setUTCMonth.apply(this._, arguments); + }, + setSeconds: function() { + d3_time_prototype.setUTCSeconds.apply(this._, arguments); + }, + setTime: function() { + d3_time_prototype.setTime.apply(this._, arguments); + } + }; + var d3_time_prototype = Date.prototype; + function d3_time_interval(local, step, number) { + function round(date) { + var d0 = local(date), d1 = offset(d0, 1); + return date - d0 < d1 - date ? d0 : d1; + } + function ceil(date) { + step(date = local(new d3_date(date - 1)), 1); + return date; + } + function offset(date, k) { + step(date = new d3_date(+date), k); + return date; + } + function range(t0, t1, dt) { + var time = ceil(t0), times = []; + if (dt > 1) { + while (time < t1) { + if (!(number(time) % dt)) times.push(new Date(+time)); + step(time, 1); + } + } else { + while (time < t1) times.push(new Date(+time)), step(time, 1); + } + return times; + } + function range_utc(t0, t1, dt) { + try { + d3_date = d3_date_utc; + var utc = new d3_date_utc(); + utc._ = t0; + return range(utc, t1, dt); + } finally { + d3_date = Date; + } + } + local.floor = local; + local.round = round; + local.ceil = ceil; + local.offset = offset; + local.range = range; + var utc = local.utc = d3_time_interval_utc(local); + utc.floor = utc; + utc.round = d3_time_interval_utc(round); + utc.ceil = d3_time_interval_utc(ceil); + utc.offset = d3_time_interval_utc(offset); + utc.range = range_utc; + return local; + } + function d3_time_interval_utc(method) { + return function(date, k) { + try { + d3_date = d3_date_utc; + var utc = new d3_date_utc(); + utc._ = date; + return method(utc, k)._; + } finally { + d3_date = Date; + } + }; + } + d3_time.year = d3_time_interval(function(date) { + date = d3_time.day(date); + date.setMonth(0, 1); + return date; + }, function(date, offset) { + date.setFullYear(date.getFullYear() + offset); + }, function(date) { + return date.getFullYear(); + }); + d3_time.years = d3_time.year.range; + d3_time.years.utc = d3_time.year.utc.range; + d3_time.day = d3_time_interval(function(date) { + var day = new d3_date(2e3, 0); + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); + return day; + }, function(date, offset) { + date.setDate(date.getDate() + offset); + }, function(date) { + return date.getDate() - 1; + }); + d3_time.days = d3_time.day.range; + d3_time.days.utc = d3_time.day.utc.range; + d3_time.dayOfYear = function(date) { + var year = d3_time.year(date); + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); + }; + [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) { + i = 7 - i; + var interval = d3_time[day] = d3_time_interval(function(date) { + (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); + return date; + }, function(date, offset) { + date.setDate(date.getDate() + Math.floor(offset) * 7); + }, function(date) { + var day = d3_time.year(date).getDay(); + return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); + }); + d3_time[day + "s"] = interval.range; + d3_time[day + "s"].utc = interval.utc.range; + d3_time[day + "OfYear"] = function(date) { + var day = d3_time.year(date).getDay(); + return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7); + }; + }); + d3_time.week = d3_time.sunday; + d3_time.weeks = d3_time.sunday.range; + d3_time.weeks.utc = d3_time.sunday.utc.range; + d3_time.weekOfYear = d3_time.sundayOfYear; + function d3_locale_timeFormat(locale) { + var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths; + function d3_time_format(template) { + var n = template.length; + function format(date) { + var string = [], i = -1, j = 0, c, p, f; + while (++i < n) { + if (template.charCodeAt(i) === 37) { + string.push(template.slice(j, i)); + if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); + if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); + string.push(c); + j = i + 1; + } + } + string.push(template.slice(j, i)); + return string.join(""); + } + format.parse = function(string) { + var d = { + y: 1900, + m: 0, + d: 1, + H: 0, + M: 0, + S: 0, + L: 0, + Z: null + }, i = d3_time_parse(d, template, string, 0); + if (i != string.length) return null; + if ("p" in d) d.H = d.H % 12 + d.p * 12; + var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)(); + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { + date.setFullYear(d.y, 0, 1); + date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); + } else date.setFullYear(d.y, d.m, d.d); + date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L); + return localZ ? date._ : date; + }; + format.toString = function() { + return template; + }; + return format; + } + function d3_time_parse(date, template, string, j) { + var c, p, t, i = 0, n = template.length, m = string.length; + while (i < n) { + if (j >= m) return -1; + c = template.charCodeAt(i++); + if (c === 37) { + t = template.charAt(i++); + p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t]; + if (!p || (j = p(date, string, j)) < 0) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + d3_time_format.utc = function(template) { + var local = d3_time_format(template); + function format(date) { + try { + d3_date = d3_date_utc; + var utc = new d3_date(); + utc._ = date; + return local(utc); + } finally { + d3_date = Date; + } + } + format.parse = function(string) { + try { + d3_date = d3_date_utc; + var date = local.parse(string); + return date && date._; + } finally { + d3_date = Date; + } + }; + format.toString = local.toString; + return format; + }; + d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti; + var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths); + locale_periods.forEach(function(p, i) { + d3_time_periodLookup.set(p.toLowerCase(), i); + }); + var d3_time_formats = { + a: function(d) { + return locale_shortDays[d.getDay()]; + }, + A: function(d) { + return locale_days[d.getDay()]; + }, + b: function(d) { + return locale_shortMonths[d.getMonth()]; + }, + B: function(d) { + return locale_months[d.getMonth()]; + }, + c: d3_time_format(locale_dateTime), + d: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + e: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + H: function(d, p) { + return d3_time_formatPad(d.getHours(), p, 2); + }, + I: function(d, p) { + return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); + }, + j: function(d, p) { + return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3); + }, + L: function(d, p) { + return d3_time_formatPad(d.getMilliseconds(), p, 3); + }, + m: function(d, p) { + return d3_time_formatPad(d.getMonth() + 1, p, 2); + }, + M: function(d, p) { + return d3_time_formatPad(d.getMinutes(), p, 2); + }, + p: function(d) { + return locale_periods[+(d.getHours() >= 12)]; + }, + S: function(d, p) { + return d3_time_formatPad(d.getSeconds(), p, 2); + }, + U: function(d, p) { + return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2); + }, + w: function(d) { + return d.getDay(); + }, + W: function(d, p) { + return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2); + }, + x: d3_time_format(locale_date), + X: d3_time_format(locale_time), + y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 100, p, 2); + }, + Y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); + }, + Z: d3_time_zone, + "%": function() { + return "%"; + } + }; + var d3_time_parsers = { + a: d3_time_parseWeekdayAbbrev, + A: d3_time_parseWeekday, + b: d3_time_parseMonthAbbrev, + B: d3_time_parseMonth, + c: d3_time_parseLocaleFull, + d: d3_time_parseDay, + e: d3_time_parseDay, + H: d3_time_parseHour24, + I: d3_time_parseHour24, + j: d3_time_parseDayOfYear, + L: d3_time_parseMilliseconds, + m: d3_time_parseMonthNumber, + M: d3_time_parseMinutes, + p: d3_time_parseAmPm, + S: d3_time_parseSeconds, + U: d3_time_parseWeekNumberSunday, + w: d3_time_parseWeekdayNumber, + W: d3_time_parseWeekNumberMonday, + x: d3_time_parseLocaleDate, + X: d3_time_parseLocaleTime, + y: d3_time_parseYear, + Y: d3_time_parseFullYear, + Z: d3_time_parseZone, + "%": d3_time_parseLiteralPercent + }; + function d3_time_parseWeekdayAbbrev(date, string, i) { + d3_time_dayAbbrevRe.lastIndex = 0; + var n = d3_time_dayAbbrevRe.exec(string.slice(i)); + return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekday(date, string, i) { + d3_time_dayRe.lastIndex = 0; + var n = d3_time_dayRe.exec(string.slice(i)); + return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseMonthAbbrev(date, string, i) { + d3_time_monthAbbrevRe.lastIndex = 0; + var n = d3_time_monthAbbrevRe.exec(string.slice(i)); + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseMonth(date, string, i) { + d3_time_monthRe.lastIndex = 0; + var n = d3_time_monthRe.exec(string.slice(i)); + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseLocaleFull(date, string, i) { + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); + } + function d3_time_parseLocaleDate(date, string, i) { + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); + } + function d3_time_parseLocaleTime(date, string, i) { + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); + } + function d3_time_parseAmPm(date, string, i) { + var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase()); + return n == null ? -1 : (date.p = n, i); + } + return d3_time_format; + } + var d3_time_formatPads = { + "-": "", + _: " ", + "0": "0" + }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/; + function d3_time_formatPad(value, fill, width) { + var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); + } + function d3_time_formatRe(names) { + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); + } + function d3_time_formatLookup(names) { + var map = new d3_Map(), i = -1, n = names.length; + while (++i < n) map.set(names[i].toLowerCase(), i); + return map; + } + function d3_time_parseWeekdayNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 1)); + return n ? (date.w = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberSunday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i)); + return n ? (date.U = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberMonday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i)); + return n ? (date.W = +n[0], i + n[0].length) : -1; + } + function d3_time_parseFullYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 4)); + return n ? (date.y = +n[0], i + n[0].length) : -1; + } + function d3_time_parseYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); + return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; + } + function d3_time_parseZone(date, string, i) { + return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string, + i + 5) : -1; + } + function d3_time_expandYear(d) { + return d + (d > 68 ? 1900 : 2e3); + } + function d3_time_parseMonthNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); + return n ? (date.m = n[0] - 1, i + n[0].length) : -1; + } + function d3_time_parseDay(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); + return n ? (date.d = +n[0], i + n[0].length) : -1; + } + function d3_time_parseDayOfYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 3)); + return n ? (date.j = +n[0], i + n[0].length) : -1; + } + function d3_time_parseHour24(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); + return n ? (date.H = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMinutes(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); + return n ? (date.M = +n[0], i + n[0].length) : -1; + } + function d3_time_parseSeconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); + return n ? (date.S = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMilliseconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.slice(i, i + 3)); + return n ? (date.L = +n[0], i + n[0].length) : -1; + } + function d3_time_zone(d) { + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = abs(z) / 60 | 0, zm = abs(z) % 60; + return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); + } + function d3_time_parseLiteralPercent(date, string, i) { + d3_time_percentRe.lastIndex = 0; + var n = d3_time_percentRe.exec(string.slice(i, i + 1)); + return n ? i + n[0].length : -1; + } + function d3_time_formatMulti(formats) { + var n = formats.length, i = -1; + while (++i < n) formats[i][0] = this(formats[i][0]); + return function(date) { + var i = 0, f = formats[i]; + while (!f[1](date)) f = formats[++i]; + return f[0](date); + }; + } + d3.locale = function(locale) { + return { + numberFormat: d3_locale_numberFormat(locale), + timeFormat: d3_locale_timeFormat(locale) + }; + }; + var d3_locale_enUS = d3.locale({ + decimal: ".", + thousands: ",", + grouping: [ 3 ], + currency: [ "$", "" ], + dateTime: "%a %b %e %X %Y", + date: "%m/%d/%Y", + time: "%H:%M:%S", + periods: [ "AM", "PM" ], + days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], + shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], + months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], + shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] + }); + d3.format = d3_locale_enUS.numberFormat; + d3.geo = {}; + function d3_adder() {} + d3_adder.prototype = { + s: 0, + t: 0, + add: function(y) { + d3_adderSum(y, this.t, d3_adderTemp); + d3_adderSum(d3_adderTemp.s, this.s, this); + if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; + }, + reset: function() { + this.s = this.t = 0; + }, + valueOf: function() { + return this.s; + } + }; + var d3_adderTemp = new d3_adder(); + function d3_adderSum(a, b, o) { + var x = o.s = a + b, bv = x - a, av = x - bv; + o.t = a - av + (b - bv); + } + d3.geo.stream = function(object, listener) { + if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { + d3_geo_streamObjectType[object.type](object, listener); + } else { + d3_geo_streamGeometry(object, listener); + } + }; + function d3_geo_streamGeometry(geometry, listener) { + if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { + d3_geo_streamGeometryType[geometry.type](geometry, listener); + } + } + var d3_geo_streamObjectType = { + Feature: function(feature, listener) { + d3_geo_streamGeometry(feature.geometry, listener); + }, + FeatureCollection: function(object, listener) { + var features = object.features, i = -1, n = features.length; + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); + } + }; + var d3_geo_streamGeometryType = { + Sphere: function(object, listener) { + listener.sphere(); + }, + Point: function(object, listener) { + object = object.coordinates; + listener.point(object[0], object[1], object[2]); + }, + MultiPoint: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]); + }, + LineString: function(object, listener) { + d3_geo_streamLine(object.coordinates, listener, 0); + }, + MultiLineString: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); + }, + Polygon: function(object, listener) { + d3_geo_streamPolygon(object.coordinates, listener); + }, + MultiPolygon: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); + }, + GeometryCollection: function(object, listener) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); + } + }; + function d3_geo_streamLine(coordinates, listener, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + listener.lineStart(); + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]); + listener.lineEnd(); + } + function d3_geo_streamPolygon(coordinates, listener) { + var i = -1, n = coordinates.length; + listener.polygonStart(); + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); + listener.polygonEnd(); + } + d3.geo.area = function(object) { + d3_geo_areaSum = 0; + d3.geo.stream(object, d3_geo_area); + return d3_geo_areaSum; + }; + var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); + var d3_geo_area = { + sphere: function() { + d3_geo_areaSum += 4 * π; + }, + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_areaRingSum.reset(); + d3_geo_area.lineStart = d3_geo_areaRingStart; + }, + polygonEnd: function() { + var area = 2 * d3_geo_areaRingSum; + d3_geo_areaSum += area < 0 ? 4 * π + area : area; + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; + } + }; + function d3_geo_areaRingStart() { + var λ00, φ00, λ0, cosφ0, sinφ0; + d3_geo_area.point = function(λ, φ) { + d3_geo_area.point = nextPoint; + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), + sinφ0 = Math.sin(φ); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + φ = φ * d3_radians / 2 + π / 4; + var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ); + d3_geo_areaRingSum.add(Math.atan2(v, u)); + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; + } + d3_geo_area.lineEnd = function() { + nextPoint(λ00, φ00); + }; + } + function d3_geo_cartesian(spherical) { + var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); + return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; + } + function d3_geo_cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + function d3_geo_cartesianCross(a, b) { + return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; + } + function d3_geo_cartesianAdd(a, b) { + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; + } + function d3_geo_cartesianScale(vector, k) { + return [ vector[0] * k, vector[1] * k, vector[2] * k ]; + } + function d3_geo_cartesianNormalize(d) { + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l; + d[1] /= l; + d[2] /= l; + } + function d3_geo_spherical(cartesian) { + return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; + } + function d3_geo_sphericalEqual(a, b) { + return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε; + } + d3.geo.bounds = function() { + var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; + var bound = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + bound.point = ringPoint; + bound.lineStart = ringStart; + bound.lineEnd = ringEnd; + dλSum = 0; + d3_geo_area.polygonStart(); + }, + polygonEnd: function() { + d3_geo_area.polygonEnd(); + bound.point = point; + bound.lineStart = lineStart; + bound.lineEnd = lineEnd; + if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; + range[0] = λ0, range[1] = λ1; + } + }; + function point(λ, φ) { + ranges.push(range = [ λ0 = λ, λ1 = λ ]); + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + function linePoint(λ, φ) { + var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); + if (p0) { + var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); + d3_geo_cartesianNormalize(inflection); + inflection = d3_geo_spherical(inflection); + var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180; + if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = inflection[1] * d3_degrees; + if (φi > φ1) φ1 = φi; + } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = -inflection[1] * d3_degrees; + if (φi < φ0) φ0 = φi; + } else { + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + if (antimeridian) { + if (λ < λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } else { + if (λ1 >= λ0) { + if (λ < λ0) λ0 = λ; + if (λ > λ1) λ1 = λ; + } else { + if (λ > λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } + } + } else { + point(λ, φ); + } + p0 = p, λ_ = λ; + } + function lineStart() { + bound.point = linePoint; + } + function lineEnd() { + range[0] = λ0, range[1] = λ1; + bound.point = point; + p0 = null; + } + function ringPoint(λ, φ) { + if (p0) { + var dλ = λ - λ_; + dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; + } else λ__ = λ, φ__ = φ; + d3_geo_area.point(λ, φ); + linePoint(λ, φ); + } + function ringStart() { + d3_geo_area.lineStart(); + } + function ringEnd() { + ringPoint(λ__, φ__); + d3_geo_area.lineEnd(); + if (abs(dλSum) > ε) λ0 = -(λ1 = 180); + range[0] = λ0, range[1] = λ1; + p0 = null; + } + function angle(λ0, λ1) { + return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; + } + function compareRanges(a, b) { + return a[0] - b[0]; + } + function withinRange(x, range) { + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; + } + return function(feature) { + φ1 = λ1 = -(λ0 = φ0 = Infinity); + ranges = []; + d3.geo.stream(feature, bound); + var n = ranges.length; + if (n) { + ranges.sort(compareRanges); + for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { + b = ranges[i]; + if (withinRange(b[0], a) || withinRange(b[1], a)) { + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; + } else { + merged.push(a = b); + } + } + var best = -Infinity, dλ; + for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { + b = merged[i]; + if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; + } + } + ranges = range = null; + return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; + }; + }(); + d3.geo.centroid = function(object) { + d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, d3_geo_centroid); + var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; + if (m < ε2) { + x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; + if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; + m = x * x + y * y + z * z; + if (m < ε2) return [ NaN, NaN ]; + } + return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; + }; + var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; + var d3_geo_centroid = { + sphere: d3_noop, + point: d3_geo_centroidPoint, + lineStart: d3_geo_centroidLineStart, + lineEnd: d3_geo_centroidLineEnd, + polygonStart: function() { + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; + }, + polygonEnd: function() { + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; + } + }; + function d3_geo_centroidPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); + } + function d3_geo_centroidPointXYZ(x, y, z) { + ++d3_geo_centroidW0; + d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; + d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; + d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; + } + function d3_geo_centroidLineStart() { + var x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroid.point = nextPoint; + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_geo_centroidLineEnd() { + d3_geo_centroid.point = d3_geo_centroidPoint; + } + function d3_geo_centroidRingStart() { + var λ00, φ00, x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ00 = λ, φ00 = φ; + d3_geo_centroid.point = nextPoint; + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + d3_geo_centroid.lineEnd = function() { + nextPoint(λ00, φ00); + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; + d3_geo_centroid.point = d3_geo_centroidPoint; + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); + d3_geo_centroidX2 += v * cx; + d3_geo_centroidY2 += v * cy; + d3_geo_centroidZ2 += v * cz; + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_geo_compose(a, b) { + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); + } + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); + }; + return compose; + } + function d3_true() { + return true; + } + function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) { + var subject = [], clip = []; + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n]; + if (d3_geo_sphericalEqual(p0, p1)) { + listener.lineStart(); + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + listener.lineEnd(); + return; + } + var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false); + a.o = b; + subject.push(a); + clip.push(b); + a = new d3_geo_clipPolygonIntersection(p1, segment, null, false); + b = new d3_geo_clipPolygonIntersection(p1, null, a, true); + a.o = b; + subject.push(a); + clip.push(b); + }); + clip.sort(compare); + d3_geo_clipPolygonLinkCircular(subject); + d3_geo_clipPolygonLinkCircular(clip); + if (!subject.length) return; + for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) { + clip[i].e = entry = !entry; + } + var start = subject[0], points, point; + while (1) { + var current = start, isSubject = true; + while (current.v) if ((current = current.n) === start) return; + points = current.z; + listener.lineStart(); + do { + current.v = current.o.v = true; + if (current.e) { + if (isSubject) { + for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.x, current.n.x, 1, listener); + } + current = current.n; + } else { + if (isSubject) { + points = current.p.z; + for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.x, current.p.x, -1, listener); + } + current = current.p; + } + current = current.o; + points = current.z; + isSubject = !isSubject; + } while (!current.v); + listener.lineEnd(); + } + } + function d3_geo_clipPolygonLinkCircular(array) { + if (!(n = array.length)) return; + var n, i = 0, a = array[0], b; + while (++i < n) { + a.n = b = array[i]; + b.p = a; + a = b; + } + a.n = b = array[0]; + b.p = a; + } + function d3_geo_clipPolygonIntersection(point, points, other, entry) { + this.x = point; + this.z = points; + this.o = other; + this.e = entry; + this.v = false; + this.n = this.p = null; + } + function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { + return function(rotate, listener) { + var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]); + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + segments = []; + polygon = []; + }, + polygonEnd: function() { + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + segments = d3.merge(segments); + var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); + if (segments.length) { + if (!polygonStarted) listener.polygonStart(), polygonStarted = true; + d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); + } else if (clipStartInside) { + if (!polygonStarted) listener.polygonStart(), polygonStarted = true; + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + if (polygonStarted) listener.polygonEnd(), polygonStarted = false; + segments = polygon = null; + }, + sphere: function() { + listener.polygonStart(); + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + listener.polygonEnd(); + } + }; + function point(λ, φ) { + var point = rotate(λ, φ); + if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ); + } + function pointLine(λ, φ) { + var point = rotate(λ, φ); + line.point(point[0], point[1]); + } + function lineStart() { + clip.point = pointLine; + line.lineStart(); + } + function lineEnd() { + clip.point = point; + line.lineEnd(); + } + var segments; + var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring; + function pointRing(λ, φ) { + ring.push([ λ, φ ]); + var point = rotate(λ, φ); + ringListener.point(point[0], point[1]); + } + function ringStart() { + ringListener.lineStart(); + ring = []; + } + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringListener.lineEnd(); + var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; + ring.pop(); + polygon.push(ring); + ring = null; + if (!n) return; + if (clean & 1) { + segment = ringSegments[0]; + var n = segment.length - 1, i = -1, point; + if (n > 0) { + if (!polygonStarted) listener.polygonStart(), polygonStarted = true; + listener.lineStart(); + while (++i < n) listener.point((point = segment[i])[0], point[1]); + listener.lineEnd(); + } + return; + } + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); + } + return clip; + }; + } + function d3_geo_clipSegmentLength1(segment) { + return segment.length > 1; + } + function d3_geo_clipBufferListener() { + var lines = [], line; + return { + lineStart: function() { + lines.push(line = []); + }, + point: function(λ, φ) { + line.push([ λ, φ ]); + }, + lineEnd: d3_noop, + buffer: function() { + var buffer = lines; + lines = []; + line = null; + return buffer; + }, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + } + }; + } + function d3_geo_clipSort(a, b) { + return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]); + } + var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]); + function d3_geo_clipAntimeridianLine(listener) { + var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; + return { + lineStart: function() { + listener.lineStart(); + clean = 1; + }, + point: function(λ1, φ1) { + var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0); + if (abs(dλ - π) < ε) { + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + listener.point(λ1, φ0); + clean = 0; + } else if (sλ0 !== sλ1 && dλ >= π) { + if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; + if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + clean = 0; + } + listener.point(λ0 = λ1, φ0 = φ1); + sλ0 = sλ1; + }, + lineEnd: function() { + listener.lineEnd(); + λ0 = φ0 = NaN; + }, + clean: function() { + return 2 - clean; + } + }; + } + function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { + var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); + return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; + } + function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { + var φ; + if (from == null) { + φ = direction * halfπ; + listener.point(-π, φ); + listener.point(0, φ); + listener.point(π, φ); + listener.point(π, 0); + listener.point(π, -φ); + listener.point(0, -φ); + listener.point(-π, -φ); + listener.point(-π, 0); + listener.point(-π, φ); + } else if (abs(from[0] - to[0]) > ε) { + var s = from[0] < to[0] ? π : -π; + φ = direction * s / 2; + listener.point(-s, φ); + listener.point(0, φ); + listener.point(s, φ); + } else { + listener.point(to[0], to[1]); + } + } + function d3_geo_pointInPolygon(point, polygon) { + var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0; + d3_geo_areaRingSum.reset(); + for (var i = 0, n = polygon.length; i < n; ++i) { + var ring = polygon[i], m = ring.length; + if (!m) continue; + var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; + while (true) { + if (j === m) j = 0; + point = ring[j]; + var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ; + d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ))); + polarAngle += antimeridian ? dλ + sdλ * τ : dλ; + if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { + var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); + d3_geo_cartesianNormalize(arc); + var intersection = d3_geo_cartesianCross(meridianNormal, arc); + d3_geo_cartesianNormalize(intersection); + var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); + if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) { + winding += antimeridian ^ dλ >= 0 ? 1 : -1; + } + } + if (!j++) break; + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; + } + } + return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ winding & 1; + } + function d3_geo_clipCircle(radius) { + var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); + return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]); + function visible(λ, φ) { + return Math.cos(λ) * Math.cos(φ) > cr; + } + function clipLine(listener) { + var point0, c0, v0, v00, clean; + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(λ, φ) { + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; + if (!point0 && (v00 = v0 = v)) listener.lineStart(); + if (v !== v0) { + point2 = intersect(point0, point1); + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { + point1[0] += ε; + point1[1] += ε; + v = visible(point1[0], point1[1]); + } + } + if (v !== v0) { + clean = 0; + if (v) { + listener.lineStart(); + point2 = intersect(point1, point0); + listener.point(point2[0], point2[1]); + } else { + point2 = intersect(point0, point1); + listener.point(point2[0], point2[1]); + listener.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + } else { + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + } + } + } + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { + listener.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) listener.lineEnd(); + point0 = null; + }, + clean: function() { + return clean | (v00 && v0) << 1; + } + }; + } + function intersect(a, b, two) { + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; + if (!determinant) return !two && a; + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); + d3_geo_cartesianAdd(A, B); + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); + if (t2 < 0) return; + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); + d3_geo_cartesianAdd(q, A); + q = d3_geo_spherical(q); + if (!two) return q; + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; + var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε; + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); + d3_geo_cartesianAdd(q1, A); + return [ q, d3_geo_spherical(q1) ]; + } + } + function code(λ, φ) { + var r = smallRadius ? radius : π - radius, code = 0; + if (λ < -r) code |= 1; else if (λ > r) code |= 2; + if (φ < -r) code |= 4; else if (φ > r) code |= 8; + return code; + } + } + function d3_geom_clipLine(x0, y0, x1, y1) { + return function(line) { + var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r; + r = x0 - ax; + if (!dx && r > 0) return; + r /= dx; + if (dx < 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } else if (dx > 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } + r = x1 - ax; + if (!dx && r < 0) return; + r /= dx; + if (dx < 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } else if (dx > 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } + r = y0 - ay; + if (!dy && r > 0) return; + r /= dy; + if (dy < 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } else if (dy > 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } + r = y1 - ay; + if (!dy && r < 0) return; + r /= dy; + if (dy < 0) { + if (r > t1) return; + if (r > t0) t0 = r; + } else if (dy > 0) { + if (r < t0) return; + if (r < t1) t1 = r; + } + if (t0 > 0) line.a = { + x: ax + t0 * dx, + y: ay + t0 * dy + }; + if (t1 < 1) line.b = { + x: ax + t1 * dx, + y: ay + t1 * dy + }; + return line; + }; + } + var d3_geo_clipExtentMAX = 1e9; + d3.geo.clipExtent = function() { + var x0, y0, x1, y1, stream, clip, clipExtent = { + stream: function(output) { + if (stream) stream.valid = false; + stream = clip(output); + stream.valid = true; + return stream; + }, + extent: function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]); + if (stream) stream.valid = false, stream = null; + return clipExtent; + } + }; + return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]); + }; + function d3_geo_clipExtent(x0, y0, x1, y1) { + return function(listener) { + var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring; + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + listener = bufferListener; + segments = []; + polygon = []; + clean = true; + }, + polygonEnd: function() { + listener = listener_; + segments = d3.merge(segments); + var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length; + if (inside || visible) { + listener.polygonStart(); + if (inside) { + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + if (visible) { + d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener); + } + listener.polygonEnd(); + } + segments = polygon = ring = null; + } + }; + function insidePolygon(p) { + var wn = 0, n = polygon.length, y = p[1]; + for (var i = 0; i < n; ++i) { + for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { + b = v[j]; + if (a[1] <= y) { + if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn; + } else { + if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn; + } + a = b; + } + } + return wn !== 0; + } + function interpolate(from, to, direction, listener) { + var a = 0, a1 = 0; + if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { + do { + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + } while ((a = (a + direction + 4) % 4) !== a1); + } else { + listener.point(to[0], to[1]); + } + } + function pointVisible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + function point(x, y) { + if (pointVisible(x, y)) listener.point(x, y); + } + var x__, y__, v__, x_, y_, v_, first, clean; + function lineStart() { + clip.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + function lineEnd() { + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferListener.rejoin(); + segments.push(bufferListener.buffer()); + } + clip.point = point; + if (v_) listener.lineEnd(); + } + function linePoint(x, y) { + x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x)); + y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y)); + var v = pointVisible(x, y); + if (polygon) ring.push([ x, y ]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + listener.lineStart(); + listener.point(x, y); + } + } else { + if (v && v_) listener.point(x, y); else { + var l = { + a: { + x: x_, + y: y_ + }, + b: { + x: x, + y: y + } + }; + if (clipLine(l)) { + if (!v_) { + listener.lineStart(); + listener.point(l.a.x, l.a.y); + } + listener.point(l.b.x, l.b.y); + if (!v) listener.lineEnd(); + clean = false; + } else if (v) { + listener.lineStart(); + listener.point(x, y); + clean = false; + } + } + } + x_ = x, y_ = y, v_ = v; + } + return clip; + }; + function corner(p, direction) { + return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; + } + function compare(a, b) { + return comparePoints(a.x, b.x); + } + function comparePoints(a, b) { + var ca = corner(a, 1), cb = corner(b, 1); + return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; + } + } + function d3_geo_conic(projectAt) { + var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); + p.parallels = function(_) { + if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); + }; + return p; + } + function d3_geo_conicEqualArea(φ0, φ1) { + var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; + function forward(λ, φ) { + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; + return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = ρ0 - y; + return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; + }; + return forward; + } + (d3.geo.conicEqualArea = function() { + return d3_geo_conic(d3_geo_conicEqualArea); + }).raw = d3_geo_conicEqualArea; + d3.geo.albers = function() { + return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); + }; + d3.geo.albersUsa = function() { + var lower48 = d3.geo.albers(); + var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); + var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); + var point, pointStream = { + point: function(x, y) { + point = [ x, y ]; + } + }, lower48Point, alaskaPoint, hawaiiPoint; + function albersUsa(coordinates) { + var x = coordinates[0], y = coordinates[1]; + point = null; + (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); + return point; + } + albersUsa.invert = function(coordinates) { + var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; + return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); + }; + albersUsa.stream = function(stream) { + var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); + return { + point: function(x, y) { + lower48Stream.point(x, y); + alaskaStream.point(x, y); + hawaiiStream.point(x, y); + }, + sphere: function() { + lower48Stream.sphere(); + alaskaStream.sphere(); + hawaiiStream.sphere(); + }, + lineStart: function() { + lower48Stream.lineStart(); + alaskaStream.lineStart(); + hawaiiStream.lineStart(); + }, + lineEnd: function() { + lower48Stream.lineEnd(); + alaskaStream.lineEnd(); + hawaiiStream.lineEnd(); + }, + polygonStart: function() { + lower48Stream.polygonStart(); + alaskaStream.polygonStart(); + hawaiiStream.polygonStart(); + }, + polygonEnd: function() { + lower48Stream.polygonEnd(); + alaskaStream.polygonEnd(); + hawaiiStream.polygonEnd(); + } + }; + }; + albersUsa.precision = function(_) { + if (!arguments.length) return lower48.precision(); + lower48.precision(_); + alaska.precision(_); + hawaii.precision(_); + return albersUsa; + }; + albersUsa.scale = function(_) { + if (!arguments.length) return lower48.scale(); + lower48.scale(_); + alaska.scale(_ * .35); + hawaii.scale(_); + return albersUsa.translate(lower48.translate()); + }; + albersUsa.translate = function(_) { + if (!arguments.length) return lower48.translate(); + var k = lower48.scale(), x = +_[0], y = +_[1]; + lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; + alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + return albersUsa; + }; + return albersUsa.scale(1070); + }; + var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_pathAreaPolygon = 0; + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; + }, + polygonEnd: function() { + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; + d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2); + } + }; + function d3_geo_pathAreaRingStart() { + var x00, y00, x0, y0; + d3_geo_pathArea.point = function(x, y) { + d3_geo_pathArea.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + function nextPoint(x, y) { + d3_geo_pathAreaPolygon += y0 * x - x0 * y; + x0 = x, y0 = y; + } + d3_geo_pathArea.lineEnd = function() { + nextPoint(x00, y00); + }; + } + var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; + var d3_geo_pathBounds = { + point: d3_geo_pathBoundsPoint, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_pathBoundsPoint(x, y) { + if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; + if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; + if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; + if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; + } + function d3_geo_pathBuffer() { + var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointCircle = d3_geo_pathBufferCircle(_); + return stream; + }, + result: function() { + if (buffer.length) { + var result = buffer.join(""); + buffer = []; + return result; + } + } + }; + function point(x, y) { + buffer.push("M", x, ",", y, pointCircle); + } + function pointLineStart(x, y) { + buffer.push("M", x, ",", y); + stream.point = pointLine; + } + function pointLine(x, y) { + buffer.push("L", x, ",", y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + buffer.push("Z"); + } + return stream; + } + function d3_geo_pathBufferCircle(radius) { + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; + } + var d3_geo_pathCentroid = { + point: d3_geo_pathCentroidPoint, + lineStart: d3_geo_pathCentroidLineStart, + lineEnd: d3_geo_pathCentroidLineEnd, + polygonStart: function() { + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; + }, + polygonEnd: function() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; + } + }; + function d3_geo_pathCentroidPoint(x, y) { + d3_geo_centroidX0 += x; + d3_geo_centroidY0 += y; + ++d3_geo_centroidZ0; + } + function d3_geo_pathCentroidLineStart() { + var x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + } + function d3_geo_pathCentroidLineEnd() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + } + function d3_geo_pathCentroidRingStart() { + var x00, y00, x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + z = y0 * x - x0 * y; + d3_geo_centroidX2 += z * (x0 + x); + d3_geo_centroidY2 += z * (y0 + y); + d3_geo_centroidZ2 += z * 3; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + d3_geo_pathCentroid.lineEnd = function() { + nextPoint(x00, y00); + }; + } + function d3_geo_pathContext(context) { + var pointRadius = 4.5; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointRadius = _; + return stream; + }, + result: d3_noop + }; + function point(x, y) { + context.moveTo(x + pointRadius, y); + context.arc(x, y, pointRadius, 0, τ); + } + function pointLineStart(x, y) { + context.moveTo(x, y); + stream.point = pointLine; + } + function pointLine(x, y) { + context.lineTo(x, y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + context.closePath(); + } + return stream; + } + function d3_geo_resample(project) { + var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; + function resample(stream) { + return (maxDepth ? resampleRecursive : resampleNone)(stream); + } + function resampleNone(stream) { + return d3_geo_transformPoint(stream, function(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + }); + } + function resampleRecursive(stream) { + var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; + var resample = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + stream.polygonStart(); + resample.lineStart = ringStart; + }, + polygonEnd: function() { + stream.polygonEnd(); + resample.lineStart = lineStart; + } + }; + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + function lineStart() { + x0 = NaN; + resample.point = linePoint; + stream.lineStart(); + } + function linePoint(λ, φ) { + var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); + resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); + stream.point(x0, y0); + } + function lineEnd() { + resample.point = point; + stream.lineEnd(); + } + function ringStart() { + lineStart(); + resample.point = ringPoint; + resample.lineEnd = ringEnd; + } + function ringPoint(λ, φ) { + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resample.point = linePoint; + } + function ringEnd() { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); + resample.lineEnd = lineEnd; + lineEnd(); + } + return resample; + } + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; + if (d2 > 4 * δ2 && depth--) { + var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); + } + } + } + resample.precision = function(_) { + if (!arguments.length) return Math.sqrt(δ2); + maxDepth = (δ2 = _ * _) > 0 && 16; + return resample; + }; + return resample; + } + d3.geo.path = function() { + var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; + function path(object) { + if (object) { + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); + if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); + d3.geo.stream(object, cacheStream); + } + return contextStream.result(); + } + path.area = function(object) { + d3_geo_pathAreaSum = 0; + d3.geo.stream(object, projectStream(d3_geo_pathArea)); + return d3_geo_pathAreaSum; + }; + path.centroid = function(object) { + d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); + return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; + }; + path.bounds = function(object) { + d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); + d3.geo.stream(object, projectStream(d3_geo_pathBounds)); + return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; + }; + path.projection = function(_) { + if (!arguments.length) return projection; + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; + return reset(); + }; + path.context = function(_) { + if (!arguments.length) return context; + contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); + return reset(); + }; + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); + return path; + }; + function reset() { + cacheStream = null; + return path; + } + return path.projection(d3.geo.albersUsa()).context(null); + }; + function d3_geo_pathProjectStream(project) { + var resample = d3_geo_resample(function(x, y) { + return project([ x * d3_degrees, y * d3_degrees ]); + }); + return function(stream) { + return d3_geo_projectionRadians(resample(stream)); + }; + } + d3.geo.transform = function(methods) { + return { + stream: function(stream) { + var transform = new d3_geo_transform(stream); + for (var k in methods) transform[k] = methods[k]; + return transform; + } + }; + }; + function d3_geo_transform(stream) { + this.stream = stream; + } + d3_geo_transform.prototype = { + point: function(x, y) { + this.stream.point(x, y); + }, + sphere: function() { + this.stream.sphere(); + }, + lineStart: function() { + this.stream.lineStart(); + }, + lineEnd: function() { + this.stream.lineEnd(); + }, + polygonStart: function() { + this.stream.polygonStart(); + }, + polygonEnd: function() { + this.stream.polygonEnd(); + } + }; + function d3_geo_transformPoint(stream, point) { + return { + point: point, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + } + d3.geo.projection = d3_geo_projection; + d3.geo.projectionMutator = d3_geo_projectionMutator; + function d3_geo_projection(project) { + return d3_geo_projectionMutator(function() { + return project; + })(); + } + function d3_geo_projectionMutator(projectAt) { + var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { + x = project(x, y); + return [ x[0] * k + δx, δy - x[1] * k ]; + }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; + function projection(point) { + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); + return [ point[0] * k + δx, δy - point[1] * k ]; + } + function invert(point) { + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); + return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; + } + projection.stream = function(output) { + if (stream) stream.valid = false; + stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output)))); + stream.valid = true; + return stream; + }; + projection.clipAngle = function(_) { + if (!arguments.length) return clipAngle; + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); + return invalidate(); + }; + projection.clipExtent = function(_) { + if (!arguments.length) return clipExtent; + clipExtent = _; + postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity; + return invalidate(); + }; + projection.scale = function(_) { + if (!arguments.length) return k; + k = +_; + return reset(); + }; + projection.translate = function(_) { + if (!arguments.length) return [ x, y ]; + x = +_[0]; + y = +_[1]; + return reset(); + }; + projection.center = function(_) { + if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; + λ = _[0] % 360 * d3_radians; + φ = _[1] % 360 * d3_radians; + return reset(); + }; + projection.rotate = function(_) { + if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; + δλ = _[0] % 360 * d3_radians; + δφ = _[1] % 360 * d3_radians; + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; + return reset(); + }; + d3.rebind(projection, projectResample, "precision"); + function reset() { + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); + var center = project(λ, φ); + δx = x - center[0] * k; + δy = y + center[1] * k; + return invalidate(); + } + function invalidate() { + if (stream) stream.valid = false, stream = null; + return projection; + } + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return reset(); + }; + } + function d3_geo_projectionRadians(stream) { + return d3_geo_transformPoint(stream, function(x, y) { + stream.point(x * d3_radians, y * d3_radians); + }); + } + function d3_geo_equirectangular(λ, φ) { + return [ λ, φ ]; + } + (d3.geo.equirectangular = function() { + return d3_geo_projection(d3_geo_equirectangular); + }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; + d3.geo.rotation = function(rotate) { + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); + function forward(coordinates) { + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + } + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + }; + return forward; + }; + function d3_geo_identityRotation(λ, φ) { + return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; + } + d3_geo_identityRotation.invert = d3_geo_equirectangular; + function d3_geo_rotation(δλ, δφ, δγ) { + return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation; + } + function d3_geo_forwardRotationλ(δλ) { + return function(λ, φ) { + return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; + }; + } + function d3_geo_rotationλ(δλ) { + var rotation = d3_geo_forwardRotationλ(δλ); + rotation.invert = d3_geo_forwardRotationλ(-δλ); + return rotation; + } + function d3_geo_rotationφγ(δφ, δγ) { + var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); + function rotation(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; + return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; + } + rotation.invert = function(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; + return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; + }; + return rotation; + } + d3.geo.circle = function() { + var origin = [ 0, 0 ], angle, precision = 6, interpolate; + function circle() { + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; + interpolate(null, null, 1, { + point: function(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= d3_degrees, x[1] *= d3_degrees; + } + }); + return { + type: "Polygon", + coordinates: [ ring ] + }; + } + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return circle; + }; + circle.angle = function(x) { + if (!arguments.length) return angle; + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); + return circle; + }; + circle.precision = function(_) { + if (!arguments.length) return precision; + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); + return circle; + }; + return circle.angle(90); + }; + function d3_geo_circleInterpolate(radius, precision) { + var cr = Math.cos(radius), sr = Math.sin(radius); + return function(from, to, direction, listener) { + var step = direction * precision; + if (from != null) { + from = d3_geo_circleAngle(cr, from); + to = d3_geo_circleAngle(cr, to); + if (direction > 0 ? from < to : from > to) from += direction * τ; + } else { + from = radius + direction * τ; + to = radius - .5 * step; + } + for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) { + listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); + } + }; + } + function d3_geo_circleAngle(cr, point) { + var a = d3_geo_cartesian(point); + a[0] -= cr; + d3_geo_cartesianNormalize(a); + var angle = d3_acos(-a[1]); + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); + } + d3.geo.distance = function(a, b) { + var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; + return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); + }; + d3.geo.graticule = function() { + var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; + function graticule() { + return { + type: "MultiLineString", + coordinates: lines() + }; + } + function lines() { + return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { + return abs(x % DX) > ε; + }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { + return abs(y % DY) > ε; + }).map(y)); + } + graticule.lines = function() { + return lines().map(function(coordinates) { + return { + type: "LineString", + coordinates: coordinates + }; + }); + }; + graticule.outline = function() { + return { + type: "Polygon", + coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] + }; + }; + graticule.extent = function(_) { + if (!arguments.length) return graticule.minorExtent(); + return graticule.majorExtent(_).minorExtent(_); + }; + graticule.majorExtent = function(_) { + if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; + X0 = +_[0][0], X1 = +_[1][0]; + Y0 = +_[0][1], Y1 = +_[1][1]; + if (X0 > X1) _ = X0, X0 = X1, X1 = _; + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; + return graticule.precision(precision); + }; + graticule.minorExtent = function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + x0 = +_[0][0], x1 = +_[1][0]; + y0 = +_[0][1], y1 = +_[1][1]; + if (x0 > x1) _ = x0, x0 = x1, x1 = _; + if (y0 > y1) _ = y0, y0 = y1, y1 = _; + return graticule.precision(precision); + }; + graticule.step = function(_) { + if (!arguments.length) return graticule.minorStep(); + return graticule.majorStep(_).minorStep(_); + }; + graticule.majorStep = function(_) { + if (!arguments.length) return [ DX, DY ]; + DX = +_[0], DY = +_[1]; + return graticule; + }; + graticule.minorStep = function(_) { + if (!arguments.length) return [ dx, dy ]; + dx = +_[0], dy = +_[1]; + return graticule; + }; + graticule.precision = function(_) { + if (!arguments.length) return precision; + precision = +_; + x = d3_geo_graticuleX(y0, y1, 90); + y = d3_geo_graticuleY(x0, x1, precision); + X = d3_geo_graticuleX(Y0, Y1, 90); + Y = d3_geo_graticuleY(X0, X1, precision); + return graticule; + }; + return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); + }; + function d3_geo_graticuleX(y0, y1, dy) { + var y = d3.range(y0, y1 - ε, dy).concat(y1); + return function(x) { + return y.map(function(y) { + return [ x, y ]; + }); + }; + } + function d3_geo_graticuleY(x0, x1, dx) { + var x = d3.range(x0, x1 - ε, dx).concat(x1); + return function(y) { + return x.map(function(x) { + return [ x, y ]; + }); + }; + } + function d3_source(d) { + return d.source; + } + function d3_target(d) { + return d.target; + } + d3.geo.greatArc = function() { + var source = d3_source, source_, target = d3_target, target_; + function greatArc() { + return { + type: "LineString", + coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] + }; + } + greatArc.distance = function() { + return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); + }; + greatArc.source = function(_) { + if (!arguments.length) return source; + source = _, source_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.target = function(_) { + if (!arguments.length) return target; + target = _, target_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.precision = function() { + return arguments.length ? greatArc : 0; + }; + return greatArc; + }; + d3.geo.interpolate = function(source, target) { + return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); + }; + function d3_geo_interpolate(x0, y0, x1, y1) { + var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); + var interpolate = d ? function(t) { + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; + return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; + } : function() { + return [ x0 * d3_degrees, y0 * d3_degrees ]; + }; + interpolate.distance = d; + return interpolate; + } + d3.geo.length = function(object) { + d3_geo_lengthSum = 0; + d3.geo.stream(object, d3_geo_length); + return d3_geo_lengthSum; + }; + var d3_geo_lengthSum; + var d3_geo_length = { + sphere: d3_noop, + point: d3_noop, + lineStart: d3_geo_lengthLineStart, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_lengthLineStart() { + var λ0, sinφ0, cosφ0; + d3_geo_length.point = function(λ, φ) { + λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); + d3_geo_length.point = nextPoint; + }; + d3_geo_length.lineEnd = function() { + d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; + }; + function nextPoint(λ, φ) { + var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); + d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; + } + } + function d3_geo_azimuthal(scale, angle) { + function azimuthal(λ, φ) { + var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); + return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; + } + azimuthal.invert = function(x, y) { + var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); + return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; + }; + return azimuthal; + } + var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { + return Math.sqrt(2 / (1 + cosλcosφ)); + }, function(ρ) { + return 2 * Math.asin(ρ / 2); + }); + (d3.geo.azimuthalEqualArea = function() { + return d3_geo_projection(d3_geo_azimuthalEqualArea); + }).raw = d3_geo_azimuthalEqualArea; + var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { + var c = Math.acos(cosλcosφ); + return c && c / Math.sin(c); + }, d3_identity); + (d3.geo.azimuthalEquidistant = function() { + return d3_geo_projection(d3_geo_azimuthalEquidistant); + }).raw = d3_geo_azimuthalEquidistant; + function d3_geo_conicConformal(φ0, φ1) { + var cosφ0 = Math.cos(φ0), t = function(φ) { + return Math.tan(π / 4 + φ / 2); + }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; + if (!n) return d3_geo_mercator; + function forward(λ, φ) { + if (F > 0) { + if (φ < -halfπ + ε) φ = -halfπ + ε; + } else { + if (φ > halfπ - ε) φ = halfπ - ε; + } + var ρ = F / Math.pow(t(φ), n); + return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); + return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ]; + }; + return forward; + } + (d3.geo.conicConformal = function() { + return d3_geo_conic(d3_geo_conicConformal); + }).raw = d3_geo_conicConformal; + function d3_geo_conicEquidistant(φ0, φ1) { + var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; + if (abs(n) < ε) return d3_geo_equirectangular; + function forward(λ, φ) { + var ρ = G - φ; + return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = G - y; + return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; + }; + return forward; + } + (d3.geo.conicEquidistant = function() { + return d3_geo_conic(d3_geo_conicEquidistant); + }).raw = d3_geo_conicEquidistant; + var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / cosλcosφ; + }, Math.atan); + (d3.geo.gnomonic = function() { + return d3_geo_projection(d3_geo_gnomonic); + }).raw = d3_geo_gnomonic; + function d3_geo_mercator(λ, φ) { + return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; + } + d3_geo_mercator.invert = function(x, y) { + return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ]; + }; + function d3_geo_mercatorProjection(project) { + var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; + m.scale = function() { + var v = scale.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.translate = function() { + var v = translate.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.clipExtent = function(_) { + var v = clipExtent.apply(m, arguments); + if (v === m) { + if (clipAuto = _ == null) { + var k = π * scale(), t = translate(); + clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); + } + } else if (clipAuto) { + v = null; + } + return v; + }; + return m.clipExtent(null); + } + (d3.geo.mercator = function() { + return d3_geo_mercatorProjection(d3_geo_mercator); + }).raw = d3_geo_mercator; + var d3_geo_orthographic = d3_geo_azimuthal(function() { + return 1; + }, Math.asin); + (d3.geo.orthographic = function() { + return d3_geo_projection(d3_geo_orthographic); + }).raw = d3_geo_orthographic; + var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / (1 + cosλcosφ); + }, function(ρ) { + return 2 * Math.atan(ρ); + }); + (d3.geo.stereographic = function() { + return d3_geo_projection(d3_geo_stereographic); + }).raw = d3_geo_stereographic; + function d3_geo_transverseMercator(λ, φ) { + return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ]; + } + d3_geo_transverseMercator.invert = function(x, y) { + return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ]; + }; + (d3.geo.transverseMercator = function() { + var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate; + projection.center = function(_) { + return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]); + }; + projection.rotate = function(_) { + return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(), + [ _[0], _[1], _[2] - 90 ]); + }; + return rotate([ 0, 0, 90 ]); + }).raw = d3_geo_transverseMercator; + d3.geom = {}; + function d3_geom_pointX(d) { + return d[0]; + } + function d3_geom_pointY(d) { + return d[1]; + } + d3.geom.hull = function(vertices) { + var x = d3_geom_pointX, y = d3_geom_pointY; + if (arguments.length) return hull(vertices); + function hull(data) { + if (data.length < 3) return []; + var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = []; + for (i = 0; i < n; i++) { + points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]); + } + points.sort(d3_geom_hullOrder); + for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]); + var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints); + var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = []; + for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]); + for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]); + return polygon; + } + hull.x = function(_) { + return arguments.length ? (x = _, hull) : x; + }; + hull.y = function(_) { + return arguments.length ? (y = _, hull) : y; + }; + return hull; + }; + function d3_geom_hullUpper(points) { + var n = points.length, hull = [ 0, 1 ], hs = 2; + for (var i = 2; i < n; i++) { + while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs; + hull[hs++] = i; + } + return hull.slice(0, hs); + } + function d3_geom_hullOrder(a, b) { + return a[0] - b[0] || a[1] - b[1]; + } + d3.geom.polygon = function(coordinates) { + d3_subclass(coordinates, d3_geom_polygonPrototype); + return coordinates; + }; + var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; + d3_geom_polygonPrototype.area = function() { + var i = -1, n = this.length, a, b = this[n - 1], area = 0; + while (++i < n) { + a = b; + b = this[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + return area * .5; + }; + d3_geom_polygonPrototype.centroid = function(k) { + var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; + if (!arguments.length) k = -1 / (6 * this.area()); + while (++i < n) { + a = b; + b = this[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [ x * k, y * k ]; + }; + d3_geom_polygonPrototype.clip = function(subject) { + var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = this[i]; + c = input[(m = input.length - closed) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + c = d; + } + if (closed) subject.push(subject[0]); + a = b; + } + return subject; + }; + function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); + } + function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); + return [ x1 + ua * x21, y1 + ua * y21 ]; + } + function d3_geom_polygonClosed(coordinates) { + var a = coordinates[0], b = coordinates[coordinates.length - 1]; + return !(a[0] - b[0] || a[1] - b[1]); + } + var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = []; + function d3_geom_voronoiBeach() { + d3_geom_voronoiRedBlackNode(this); + this.edge = this.site = this.circle = null; + } + function d3_geom_voronoiCreateBeach(site) { + var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach(); + beach.site = site; + return beach; + } + function d3_geom_voronoiDetachBeach(beach) { + d3_geom_voronoiDetachCircle(beach); + d3_geom_voronoiBeaches.remove(beach); + d3_geom_voronoiBeachPool.push(beach); + d3_geom_voronoiRedBlackNode(beach); + } + function d3_geom_voronoiRemoveBeach(beach) { + var circle = beach.circle, x = circle.x, y = circle.cy, vertex = { + x: x, + y: y + }, previous = beach.P, next = beach.N, disappearing = [ beach ]; + d3_geom_voronoiDetachBeach(beach); + var lArc = previous; + while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) { + previous = lArc.P; + disappearing.unshift(lArc); + d3_geom_voronoiDetachBeach(lArc); + lArc = previous; + } + disappearing.unshift(lArc); + d3_geom_voronoiDetachCircle(lArc); + var rArc = next; + while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) { + next = rArc.N; + disappearing.push(rArc); + d3_geom_voronoiDetachBeach(rArc); + rArc = next; + } + disappearing.push(rArc); + d3_geom_voronoiDetachCircle(rArc); + var nArcs = disappearing.length, iArc; + for (iArc = 1; iArc < nArcs; ++iArc) { + rArc = disappearing[iArc]; + lArc = disappearing[iArc - 1]; + d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex); + } + lArc = disappearing[0]; + rArc = disappearing[nArcs - 1]; + rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex); + d3_geom_voronoiAttachCircle(lArc); + d3_geom_voronoiAttachCircle(rArc); + } + function d3_geom_voronoiAddBeach(site) { + var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._; + while (node) { + dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x; + if (dxl > ε) node = node.L; else { + dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix); + if (dxr > ε) { + if (!node.R) { + lArc = node; + break; + } + node = node.R; + } else { + if (dxl > -ε) { + lArc = node.P; + rArc = node; + } else if (dxr > -ε) { + lArc = node; + rArc = node.N; + } else { + lArc = rArc = node; + } + break; + } + } + } + var newArc = d3_geom_voronoiCreateBeach(site); + d3_geom_voronoiBeaches.insert(lArc, newArc); + if (!lArc && !rArc) return; + if (lArc === rArc) { + d3_geom_voronoiDetachCircle(lArc); + rArc = d3_geom_voronoiCreateBeach(lArc.site); + d3_geom_voronoiBeaches.insert(newArc, rArc); + newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site); + d3_geom_voronoiAttachCircle(lArc); + d3_geom_voronoiAttachCircle(rArc); + return; + } + if (!rArc) { + newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site); + return; + } + d3_geom_voronoiDetachCircle(lArc); + d3_geom_voronoiDetachCircle(rArc); + var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = { + x: (cy * hb - by * hc) / d + ax, + y: (bx * hc - cx * hb) / d + ay + }; + d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex); + newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex); + rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex); + d3_geom_voronoiAttachCircle(lArc); + d3_geom_voronoiAttachCircle(rArc); + } + function d3_geom_voronoiLeftBreakPoint(arc, directrix) { + var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix; + if (!pby2) return rfocx; + var lArc = arc.P; + if (!lArc) return -Infinity; + site = lArc.site; + var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix; + if (!plby2) return lfocx; + var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2; + if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx; + return (rfocx + lfocx) / 2; + } + function d3_geom_voronoiRightBreakPoint(arc, directrix) { + var rArc = arc.N; + if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix); + var site = arc.site; + return site.y === directrix ? site.x : Infinity; + } + function d3_geom_voronoiCell(site) { + this.site = site; + this.edges = []; + } + d3_geom_voronoiCell.prototype.prepare = function() { + var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge; + while (iHalfEdge--) { + edge = halfEdges[iHalfEdge].edge; + if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1); + } + halfEdges.sort(d3_geom_voronoiHalfEdgeOrder); + return halfEdges.length; + }; + function d3_geom_voronoiCloseCells(extent) { + var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end; + while (iCell--) { + cell = cells[iCell]; + if (!cell || !cell.prepare()) continue; + halfEdges = cell.edges; + nHalfEdges = halfEdges.length; + iHalfEdge = 0; + while (iHalfEdge < nHalfEdges) { + end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y; + start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y; + if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) { + halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? { + x: x0, + y: abs(x2 - x0) < ε ? y2 : y1 + } : abs(y3 - y1) < ε && x1 - x3 > ε ? { + x: abs(y2 - y1) < ε ? x2 : x1, + y: y1 + } : abs(x3 - x1) < ε && y3 - y0 > ε ? { + x: x1, + y: abs(x2 - x1) < ε ? y2 : y0 + } : abs(y3 - y0) < ε && x3 - x0 > ε ? { + x: abs(y2 - y0) < ε ? x2 : x0, + y: y0 + } : null), cell.site, null)); + ++nHalfEdges; + } + } + } + } + function d3_geom_voronoiHalfEdgeOrder(a, b) { + return b.angle - a.angle; + } + function d3_geom_voronoiCircle() { + d3_geom_voronoiRedBlackNode(this); + this.x = this.y = this.arc = this.site = this.cy = null; + } + function d3_geom_voronoiAttachCircle(arc) { + var lArc = arc.P, rArc = arc.N; + if (!lArc || !rArc) return; + var lSite = lArc.site, cSite = arc.site, rSite = rArc.site; + if (lSite === rSite) return; + var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by; + var d = 2 * (ax * cy - ay * cx); + if (d >= -ε2) return; + var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by; + var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle(); + circle.arc = arc; + circle.site = cSite; + circle.x = x + bx; + circle.y = cy + Math.sqrt(x * x + y * y); + circle.cy = cy; + arc.circle = circle; + var before = null, node = d3_geom_voronoiCircles._; + while (node) { + if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) { + if (node.L) node = node.L; else { + before = node.P; + break; + } + } else { + if (node.R) node = node.R; else { + before = node; + break; + } + } + } + d3_geom_voronoiCircles.insert(before, circle); + if (!before) d3_geom_voronoiFirstCircle = circle; + } + function d3_geom_voronoiDetachCircle(arc) { + var circle = arc.circle; + if (circle) { + if (!circle.P) d3_geom_voronoiFirstCircle = circle.N; + d3_geom_voronoiCircles.remove(circle); + d3_geom_voronoiCirclePool.push(circle); + d3_geom_voronoiRedBlackNode(circle); + arc.circle = null; + } + } + function d3_geom_voronoiClipEdges(extent) { + var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e; + while (i--) { + e = edges[i]; + if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) { + e.a = e.b = null; + edges.splice(i, 1); + } + } + } + function d3_geom_voronoiConnectEdge(edge, extent) { + var vb = edge.b; + if (vb) return true; + var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb; + if (ry === ly) { + if (fx < x0 || fx >= x1) return; + if (lx > rx) { + if (!va) va = { + x: fx, + y: y0 + }; else if (va.y >= y1) return; + vb = { + x: fx, + y: y1 + }; + } else { + if (!va) va = { + x: fx, + y: y1 + }; else if (va.y < y0) return; + vb = { + x: fx, + y: y0 + }; + } + } else { + fm = (lx - rx) / (ry - ly); + fb = fy - fm * fx; + if (fm < -1 || fm > 1) { + if (lx > rx) { + if (!va) va = { + x: (y0 - fb) / fm, + y: y0 + }; else if (va.y >= y1) return; + vb = { + x: (y1 - fb) / fm, + y: y1 + }; + } else { + if (!va) va = { + x: (y1 - fb) / fm, + y: y1 + }; else if (va.y < y0) return; + vb = { + x: (y0 - fb) / fm, + y: y0 + }; + } + } else { + if (ly < ry) { + if (!va) va = { + x: x0, + y: fm * x0 + fb + }; else if (va.x >= x1) return; + vb = { + x: x1, + y: fm * x1 + fb + }; + } else { + if (!va) va = { + x: x1, + y: fm * x1 + fb + }; else if (va.x < x0) return; + vb = { + x: x0, + y: fm * x0 + fb + }; + } + } + } + edge.a = va; + edge.b = vb; + return true; + } + function d3_geom_voronoiEdge(lSite, rSite) { + this.l = lSite; + this.r = rSite; + this.a = this.b = null; + } + function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) { + var edge = new d3_geom_voronoiEdge(lSite, rSite); + d3_geom_voronoiEdges.push(edge); + if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va); + if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb); + d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite)); + d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite)); + return edge; + } + function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) { + var edge = new d3_geom_voronoiEdge(lSite, null); + edge.a = va; + edge.b = vb; + d3_geom_voronoiEdges.push(edge); + return edge; + } + function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) { + if (!edge.a && !edge.b) { + edge.a = vertex; + edge.l = lSite; + edge.r = rSite; + } else if (edge.l === rSite) { + edge.b = vertex; + } else { + edge.a = vertex; + } + } + function d3_geom_voronoiHalfEdge(edge, lSite, rSite) { + var va = edge.a, vb = edge.b; + this.edge = edge; + this.site = lSite; + this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y); + } + d3_geom_voronoiHalfEdge.prototype = { + start: function() { + return this.edge.l === this.site ? this.edge.a : this.edge.b; + }, + end: function() { + return this.edge.l === this.site ? this.edge.b : this.edge.a; + } + }; + function d3_geom_voronoiRedBlackTree() { + this._ = null; + } + function d3_geom_voronoiRedBlackNode(node) { + node.U = node.C = node.L = node.R = node.P = node.N = null; + } + d3_geom_voronoiRedBlackTree.prototype = { + insert: function(after, node) { + var parent, grandpa, uncle; + if (after) { + node.P = after; + node.N = after.N; + if (after.N) after.N.P = node; + after.N = node; + if (after.R) { + after = after.R; + while (after.L) after = after.L; + after.L = node; + } else { + after.R = node; + } + parent = after; + } else if (this._) { + after = d3_geom_voronoiRedBlackFirst(this._); + node.P = null; + node.N = after; + after.P = after.L = node; + parent = after; + } else { + node.P = node.N = null; + this._ = node; + parent = null; + } + node.L = node.R = null; + node.U = parent; + node.C = true; + after = node; + while (parent && parent.C) { + grandpa = parent.U; + if (parent === grandpa.L) { + uncle = grandpa.R; + if (uncle && uncle.C) { + parent.C = uncle.C = false; + grandpa.C = true; + after = grandpa; + } else { + if (after === parent.R) { + d3_geom_voronoiRedBlackRotateLeft(this, parent); + after = parent; + parent = after.U; + } + parent.C = false; + grandpa.C = true; + d3_geom_voronoiRedBlackRotateRight(this, grandpa); + } + } else { + uncle = grandpa.L; + if (uncle && uncle.C) { + parent.C = uncle.C = false; + grandpa.C = true; + after = grandpa; + } else { + if (after === parent.L) { + d3_geom_voronoiRedBlackRotateRight(this, parent); + after = parent; + parent = after.U; + } + parent.C = false; + grandpa.C = true; + d3_geom_voronoiRedBlackRotateLeft(this, grandpa); + } + } + parent = after.U; + } + this._.C = false; + }, + remove: function(node) { + if (node.N) node.N.P = node.P; + if (node.P) node.P.N = node.N; + node.N = node.P = null; + var parent = node.U, sibling, left = node.L, right = node.R, next, red; + if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right); + if (parent) { + if (parent.L === node) parent.L = next; else parent.R = next; + } else { + this._ = next; + } + if (left && right) { + red = next.C; + next.C = node.C; + next.L = left; + left.U = next; + if (next !== right) { + parent = next.U; + next.U = node.U; + node = next.R; + parent.L = node; + next.R = right; + right.U = next; + } else { + next.U = parent; + parent = next; + node = next.R; + } + } else { + red = node.C; + node = next; + } + if (node) node.U = parent; + if (red) return; + if (node && node.C) { + node.C = false; + return; + } + do { + if (node === this._) break; + if (node === parent.L) { + sibling = parent.R; + if (sibling.C) { + sibling.C = false; + parent.C = true; + d3_geom_voronoiRedBlackRotateLeft(this, parent); + sibling = parent.R; + } + if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) { + if (!sibling.R || !sibling.R.C) { + sibling.L.C = false; + sibling.C = true; + d3_geom_voronoiRedBlackRotateRight(this, sibling); + sibling = parent.R; + } + sibling.C = parent.C; + parent.C = sibling.R.C = false; + d3_geom_voronoiRedBlackRotateLeft(this, parent); + node = this._; + break; + } + } else { + sibling = parent.L; + if (sibling.C) { + sibling.C = false; + parent.C = true; + d3_geom_voronoiRedBlackRotateRight(this, parent); + sibling = parent.L; + } + if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) { + if (!sibling.L || !sibling.L.C) { + sibling.R.C = false; + sibling.C = true; + d3_geom_voronoiRedBlackRotateLeft(this, sibling); + sibling = parent.L; + } + sibling.C = parent.C; + parent.C = sibling.L.C = false; + d3_geom_voronoiRedBlackRotateRight(this, parent); + node = this._; + break; + } + } + sibling.C = true; + node = parent; + parent = parent.U; + } while (!node.C); + if (node) node.C = false; + } + }; + function d3_geom_voronoiRedBlackRotateLeft(tree, node) { + var p = node, q = node.R, parent = p.U; + if (parent) { + if (parent.L === p) parent.L = q; else parent.R = q; + } else { + tree._ = q; + } + q.U = parent; + p.U = q; + p.R = q.L; + if (p.R) p.R.U = p; + q.L = p; + } + function d3_geom_voronoiRedBlackRotateRight(tree, node) { + var p = node, q = node.L, parent = p.U; + if (parent) { + if (parent.L === p) parent.L = q; else parent.R = q; + } else { + tree._ = q; + } + q.U = parent; + p.U = q; + p.L = q.R; + if (p.L) p.L.U = p; + q.R = p; + } + function d3_geom_voronoiRedBlackFirst(node) { + while (node.L) node = node.L; + return node; + } + function d3_geom_voronoi(sites, bbox) { + var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle; + d3_geom_voronoiEdges = []; + d3_geom_voronoiCells = new Array(sites.length); + d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree(); + d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree(); + while (true) { + circle = d3_geom_voronoiFirstCircle; + if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) { + if (site.x !== x0 || site.y !== y0) { + d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site); + d3_geom_voronoiAddBeach(site); + x0 = site.x, y0 = site.y; + } + site = sites.pop(); + } else if (circle) { + d3_geom_voronoiRemoveBeach(circle.arc); + } else { + break; + } + } + if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox); + var diagram = { + cells: d3_geom_voronoiCells, + edges: d3_geom_voronoiEdges + }; + d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null; + return diagram; + } + function d3_geom_voronoiVertexOrder(a, b) { + return b.y - a.y || b.x - a.x; + } + d3.geom.voronoi = function(points) { + var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent; + if (points) return voronoi(points); + function voronoi(data) { + var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1]; + d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) { + var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) { + var s = e.start(); + return [ s.x, s.y ]; + }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : []; + polygon.point = data[i]; + }); + return polygons; + } + function sites(data) { + return data.map(function(d, i) { + return { + x: Math.round(fx(d, i) / ε) * ε, + y: Math.round(fy(d, i) / ε) * ε, + i: i + }; + }); + } + voronoi.links = function(data) { + return d3_geom_voronoi(sites(data)).edges.filter(function(edge) { + return edge.l && edge.r; + }).map(function(edge) { + return { + source: data[edge.l.i], + target: data[edge.r.i] + }; + }); + }; + voronoi.triangles = function(data) { + var triangles = []; + d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) { + var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l; + while (++j < m) { + e0 = e1; + s0 = s1; + e1 = edges[j].edge; + s1 = e1.l === site ? e1.r : e1.l; + if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) { + triangles.push([ data[i], data[s0.i], data[s1.i] ]); + } + } + }); + return triangles; + }; + voronoi.x = function(_) { + return arguments.length ? (fx = d3_functor(x = _), voronoi) : x; + }; + voronoi.y = function(_) { + return arguments.length ? (fy = d3_functor(y = _), voronoi) : y; + }; + voronoi.clipExtent = function(_) { + if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent; + clipExtent = _ == null ? d3_geom_voronoiClipExtent : _; + return voronoi; + }; + voronoi.size = function(_) { + if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1]; + return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); + }; + return voronoi; + }; + var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ]; + function d3_geom_voronoiTriangleArea(a, b, c) { + return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y); + } + d3.geom.delaunay = function(vertices) { + return d3.geom.voronoi().triangles(vertices); + }; + d3.geom.quadtree = function(points, x1, y1, x2, y2) { + var x = d3_geom_pointX, y = d3_geom_pointY, compat; + if (compat = arguments.length) { + x = d3_geom_quadtreeCompatX; + y = d3_geom_quadtreeCompatY; + if (compat === 3) { + y2 = y1; + x2 = x1; + y1 = x1 = 0; + } + return quadtree(points); + } + function quadtree(data) { + var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; + if (x1 != null) { + x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; + } else { + x2_ = y2_ = -(x1_ = y1_ = Infinity); + xs = [], ys = []; + n = data.length; + if (compat) for (i = 0; i < n; ++i) { + d = data[i]; + if (d.x < x1_) x1_ = d.x; + if (d.y < y1_) y1_ = d.y; + if (d.x > x2_) x2_ = d.x; + if (d.y > y2_) y2_ = d.y; + xs.push(d.x); + ys.push(d.y); + } else for (i = 0; i < n; ++i) { + var x_ = +fx(d = data[i], i), y_ = +fy(d, i); + if (x_ < x1_) x1_ = x_; + if (y_ < y1_) y1_ = y_; + if (x_ > x2_) x2_ = x_; + if (y_ > y2_) y2_ = y_; + xs.push(x_); + ys.push(y_); + } + } + var dx = x2_ - x1_, dy = y2_ - y1_; + if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; + function insert(n, d, x, y, x1, y1, x2, y2) { + if (isNaN(x) || isNaN(y)) return; + if (n.leaf) { + var nx = n.x, ny = n.y; + if (nx != null) { + if (abs(nx - x) + abs(ny - y) < .01) { + insertChild(n, d, x, y, x1, y1, x2, y2); + } else { + var nPoint = n.point; + n.x = n.y = n.point = null; + insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } else { + n.x = x, n.y = y, n.point = d; + } + } else { + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } + function insertChild(n, d, x, y, x1, y1, x2, y2) { + var xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right; + n.leaf = false; + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); + if (right) x1 = xm; else x2 = xm; + if (below) y1 = ym; else y2 = ym; + insert(n, d, x, y, x1, y1, x2, y2); + } + var root = d3_geom_quadtreeNode(); + root.add = function(d) { + insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); + }; + root.visit = function(f) { + d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); + }; + root.find = function(point) { + return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_); + }; + i = -1; + if (x1 == null) { + while (++i < n) { + insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); + } + --i; + } else data.forEach(root.add); + xs = ys = data = d = null; + return root; + } + quadtree.x = function(_) { + return arguments.length ? (x = _, quadtree) : x; + }; + quadtree.y = function(_) { + return arguments.length ? (y = _, quadtree) : y; + }; + quadtree.extent = function(_) { + if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], + y2 = +_[1][1]; + return quadtree; + }; + quadtree.size = function(_) { + if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; + return quadtree; + }; + return quadtree; + }; + function d3_geom_quadtreeCompatX(d) { + return d.x; + } + function d3_geom_quadtreeCompatY(d) { + return d.y; + } + function d3_geom_quadtreeNode() { + return { + leaf: true, + nodes: [], + point: null, + x: null, + y: null + }; + } + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { + if (!f(node, x1, y1, x2, y2)) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); + } + } + function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) { + var minDistance2 = Infinity, closestPoint; + (function find(node, x1, y1, x2, y2) { + if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return; + if (point = node.point) { + var point, dx = x - point[0], dy = y - point[1], distance2 = dx * dx + dy * dy; + if (distance2 < minDistance2) { + var distance = Math.sqrt(minDistance2 = distance2); + x0 = x - distance, y0 = y - distance; + x3 = x + distance, y3 = y + distance; + closestPoint = point; + } + } + var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym; + for (var i = below << 1 | right, j = i + 4; i < j; ++i) { + if (node = children[i & 3]) switch (i & 3) { + case 0: + find(node, x1, y1, xm, ym); + break; + + case 1: + find(node, xm, y1, x2, ym); + break; + + case 2: + find(node, x1, ym, xm, y2); + break; + + case 3: + find(node, xm, ym, x2, y2); + break; + } + } + })(root, x0, y0, x3, y3); + return closestPoint; + } + d3.interpolateRgb = d3_interpolateRgb; + function d3_interpolateRgb(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; + return function(t) { + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); + }; + } + d3.interpolateObject = d3_interpolateObject; + function d3_interpolateObject(a, b) { + var i = {}, c = {}, k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolate(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; + } + d3.interpolateNumber = d3_interpolateNumber; + function d3_interpolateNumber(a, b) { + a = +a, b = +b; + return function(t) { + return a * (1 - t) + b * t; + }; + } + d3.interpolateString = d3_interpolateString; + function d3_interpolateString(a, b) { + var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = []; + a = a + "", b = b + ""; + while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) { + if ((bs = bm.index) > bi) { + bs = b.slice(bi, bs); + if (s[i]) s[i] += bs; else s[++i] = bs; + } + if ((am = am[0]) === (bm = bm[0])) { + if (s[i]) s[i] += bm; else s[++i] = bm; + } else { + s[++i] = null; + q.push({ + i: i, + x: d3_interpolateNumber(am, bm) + }); + } + bi = d3_interpolate_numberB.lastIndex; + } + if (bi < b.length) { + bs = b.slice(bi); + if (s[i]) s[i] += bs; else s[++i] = bs; + } + return s.length < 2 ? q[0] ? (b = q[0].x, function(t) { + return b(t) + ""; + }) : function() { + return b; + } : (b = q.length, function(t) { + for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }); + } + var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g"); + d3.interpolate = d3_interpolate; + function d3_interpolate(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; + return f; + } + d3.interpolators = [ function(a, b) { + var t = typeof b; + return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b); + } ]; + d3.interpolateArray = d3_interpolateArray; + function d3_interpolateArray(a, b) { + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); + for (;i < na; ++i) c[i] = a[i]; + for (;i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; + } + var d3_ease_default = function() { + return d3_identity; + }; + var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { + return d3_ease_quad; + }, + cubic: function() { + return d3_ease_cubic; + }, + sin: function() { + return d3_ease_sin; + }, + exp: function() { + return d3_ease_exp; + }, + circle: function() { + return d3_ease_circle; + }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { + return d3_ease_bounce; + } + }); + var d3_ease_mode = d3.map({ + "in": d3_identity, + out: d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { + return d3_ease_reflect(d3_ease_reverse(f)); + } + }); + d3.ease = function(name) { + var i = name.indexOf("-"), t = i >= 0 ? name.slice(0, i) : name, m = i >= 0 ? name.slice(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_identity; + return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1)))); + }; + function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; + } + function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; + } + function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); + }; + } + function d3_ease_quad(t) { + return t * t; + } + function d3_ease_cubic(t) { + return t * t * t; + } + function d3_ease_cubicInOut(t) { + if (t <= 0) return 0; + if (t >= 1) return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); + } + function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; + } + function d3_ease_sin(t) { + return 1 - Math.cos(t * halfπ); + } + function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); + } + function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); + } + function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = .45; + if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4; + return function(t) { + return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p); + }; + } + function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; + } + function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + } + d3.interpolateHcl = d3_interpolateHcl; + function d3_interpolateHcl(a, b) { + a = d3.hcl(a); + b = d3.hcl(b); + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; + if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; + }; + } + d3.interpolateHsl = d3_interpolateHsl; + function d3_interpolateHsl(a, b) { + a = d3.hsl(a); + b = d3.hsl(b); + var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; + if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; + }; + } + d3.interpolateLab = d3_interpolateLab; + function d3_interpolateLab(a, b) { + a = d3.lab(a); + b = d3.lab(b); + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; + return function(t) { + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; + }; + } + d3.interpolateRound = d3_interpolateRound; + function d3_interpolateRound(a, b) { + b -= a; + return function(t) { + return Math.round(a + b * t); + }; + } + d3.transform = function(string) { + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + if (string != null) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + } + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); + }; + function d3_transform(m) { + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; + this.translate = [ m.e, m.f ]; + this.scale = [ kx, ky ]; + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; + } + d3_transform.prototype.toString = function() { + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; + }; + function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; + } + function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; + } + var d3_transformIdentity = { + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0 + }; + d3.interpolateTransform = d3_interpolateTransform; + function d3_interpolateTransform(a, b) { + var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({ + i: 1, + x: d3_interpolateNumber(ta[0], tb[0]) + }, { + i: 3, + x: d3_interpolateNumber(ta[1], tb[1]) + }); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; + q.push({ + i: s.push(s.pop() + "rotate(", null, ")") - 2, + x: d3_interpolateNumber(ra, rb) + }); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + if (wa != wb) { + q.push({ + i: s.push(s.pop() + "skewX(", null, ")") - 2, + x: d3_interpolateNumber(wa, wb) + }); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({ + i: n - 4, + x: d3_interpolateNumber(ka[0], kb[0]) + }, { + i: n - 2, + x: d3_interpolateNumber(ka[1], kb[1]) + }); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + function d3_uninterpolateNumber(a, b) { + b = (b -= a = +a) || 1 / b; + return function(x) { + return (x - a) / b; + }; + } + function d3_uninterpolateClamp(a, b) { + b = (b -= a = +a) || 1 / b; + return function(x) { + return Math.max(0, Math.min(1, (x - a) / b)); + }; + } + d3.layout = {}; + d3.layout.bundle = function() { + return function(links) { + var paths = [], i = -1, n = links.length; + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); + return paths; + }; + }; + function d3_layout_bundlePath(link) { + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; + while (start !== lca) { + start = start.parent; + points.push(start); + } + var k = points.length; + while (end !== lca) { + points.splice(k, 0, end); + end = end.parent; + } + return points; + } + function d3_layout_bundleAncestors(node) { + var ancestors = [], parent = node.parent; + while (parent != null) { + ancestors.push(node); + node = parent; + parent = parent.parent; + } + ancestors.push(node); + return ancestors; + } + function d3_layout_bundleLeastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; + while (aNode === bNode) { + sharedNode = aNode; + aNode = aNodes.pop(); + bNode = bNodes.pop(); + } + return sharedNode; + } + d3.layout.chord = function() { + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; + function relayout() { + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; + chords = []; + groups = []; + k = 0, i = -1; + while (++i < n) { + x = 0, j = -1; + while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3.range(n)); + k += x; + } + if (sortGroups) { + groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); + }); + } + if (sortSubgroups) { + subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); + } + k = (τ - padding * n) / k; + x = 0, i = -1; + while (++i < n) { + x0 = x, j = -1; + while (++j < n) { + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; + subgroups[di + "-" + dj] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: (x - x0) / k + }; + x += padding; + } + i = -1; + while (++i < n) { + j = i - 1; + while (++j < n) { + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; + if (source.value || target.value) { + chords.push(source.value < target.value ? { + source: target, + target: source + } : { + source: source, + target: target + }); + } + } + } + if (sortChords) resort(); + } + function resort() { + chords.sort(function(a, b) { + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); + }); + } + chord.matrix = function(x) { + if (!arguments.length) return matrix; + n = (matrix = x) && matrix.length; + chords = groups = null; + return chord; + }; + chord.padding = function(x) { + if (!arguments.length) return padding; + padding = x; + chords = groups = null; + return chord; + }; + chord.sortGroups = function(x) { + if (!arguments.length) return sortGroups; + sortGroups = x; + chords = groups = null; + return chord; + }; + chord.sortSubgroups = function(x) { + if (!arguments.length) return sortSubgroups; + sortSubgroups = x; + chords = null; + return chord; + }; + chord.sortChords = function(x) { + if (!arguments.length) return sortChords; + sortChords = x; + if (chords) resort(); + return chord; + }; + chord.chords = function() { + if (!chords) relayout(); + return chords; + }; + chord.groups = function() { + if (!groups) relayout(); + return groups; + }; + return chord; + }; + d3.layout.force = function() { + var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges; + function repulse(node) { + return function(quad, x1, _, x2) { + if (quad.point !== node) { + var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy; + if (dw * dw / theta2 < dn) { + if (dn < chargeDistance2) { + var k = quad.charge / dn; + node.px -= dx * k; + node.py -= dy * k; + } + return true; + } + if (quad.point && dn && dn < chargeDistance2) { + var k = quad.pointCharge / dn; + node.px -= dx * k; + node.py -= dy * k; + } + } + return !quad.charge; + }; + } + force.tick = function() { + if ((alpha *= .99) < .005) { + event.end({ + type: "end", + alpha: alpha = 0 + }); + return true; + } + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; + for (i = 0; i < m; ++i) { + o = links[i]; + s = o.source; + t = o.target; + x = t.x - s.x; + y = t.y - s.y; + if (l = x * x + y * y) { + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; + x *= l; + y *= l; + t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.y -= y * k; + s.x += x * (k = 1 - k); + s.y += y * k; + } + } + if (k = alpha * gravity) { + x = size[0] / 2; + y = size[1] / 2; + i = -1; + if (k) while (++i < n) { + o = nodes[i]; + o.x += (x - o.x) * k; + o.y += (y - o.y) * k; + } + } + if (charge) { + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); + i = -1; + while (++i < n) { + if (!(o = nodes[i]).fixed) { + q.visit(repulse(o)); + } + } + } + i = -1; + while (++i < n) { + o = nodes[i]; + if (o.fixed) { + o.x = o.px; + o.y = o.py; + } else { + o.x -= (o.px - (o.px = o.x)) * friction; + o.y -= (o.py - (o.py = o.y)) * friction; + } + } + event.tick({ + type: "tick", + alpha: alpha + }); + }; + force.nodes = function(x) { + if (!arguments.length) return nodes; + nodes = x; + return force; + }; + force.links = function(x) { + if (!arguments.length) return links; + links = x; + return force; + }; + force.size = function(x) { + if (!arguments.length) return size; + size = x; + return force; + }; + force.linkDistance = function(x) { + if (!arguments.length) return linkDistance; + linkDistance = typeof x === "function" ? x : +x; + return force; + }; + force.distance = force.linkDistance; + force.linkStrength = function(x) { + if (!arguments.length) return linkStrength; + linkStrength = typeof x === "function" ? x : +x; + return force; + }; + force.friction = function(x) { + if (!arguments.length) return friction; + friction = +x; + return force; + }; + force.charge = function(x) { + if (!arguments.length) return charge; + charge = typeof x === "function" ? x : +x; + return force; + }; + force.chargeDistance = function(x) { + if (!arguments.length) return Math.sqrt(chargeDistance2); + chargeDistance2 = x * x; + return force; + }; + force.gravity = function(x) { + if (!arguments.length) return gravity; + gravity = +x; + return force; + }; + force.theta = function(x) { + if (!arguments.length) return Math.sqrt(theta2); + theta2 = x * x; + return force; + }; + force.alpha = function(x) { + if (!arguments.length) return alpha; + x = +x; + if (alpha) { + if (x > 0) alpha = x; else alpha = 0; + } else if (x > 0) { + event.start({ + type: "start", + alpha: alpha = x + }); + d3.timer(force.tick); + } + return force; + }; + force.start = function() { + var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; + for (i = 0; i < n; ++i) { + (o = nodes[i]).index = i; + o.weight = 0; + } + for (i = 0; i < m; ++i) { + o = links[i]; + if (typeof o.source == "number") o.source = nodes[o.source]; + if (typeof o.target == "number") o.target = nodes[o.target]; + ++o.source.weight; + ++o.target.weight; + } + for (i = 0; i < n; ++i) { + o = nodes[i]; + if (isNaN(o.x)) o.x = position("x", w); + if (isNaN(o.y)) o.y = position("y", h); + if (isNaN(o.px)) o.px = o.x; + if (isNaN(o.py)) o.py = o.y; + } + distances = []; + if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; + strengths = []; + if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; + charges = []; + if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; + function position(dimension, size) { + if (!neighbors) { + neighbors = new Array(n); + for (j = 0; j < n; ++j) { + neighbors[j] = []; + } + for (j = 0; j < m; ++j) { + var o = links[j]; + neighbors[o.source.index].push(o.target); + neighbors[o.target.index].push(o.source); + } + } + var candidates = neighbors[i], j = -1, m = candidates.length, x; + while (++j < m) if (!isNaN(x = candidates[j][dimension])) return x; + return Math.random() * size; + } + return force.resume(); + }; + force.resume = function() { + return force.alpha(.1); + }; + force.stop = function() { + return force.alpha(0); + }; + force.drag = function() { + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); + if (!arguments.length) return drag; + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); + }; + function dragmove(d) { + d.px = d3.event.x, d.py = d3.event.y; + force.resume(); + } + return d3.rebind(force, event, "on"); + }; + function d3_layout_forceDragstart(d) { + d.fixed |= 2; + } + function d3_layout_forceDragend(d) { + d.fixed &= ~6; + } + function d3_layout_forceMouseover(d) { + d.fixed |= 4; + d.px = d.x, d.py = d.y; + } + function d3_layout_forceMouseout(d) { + d.fixed &= ~4; + } + function d3_layout_forceAccumulate(quad, alpha, charges) { + var cx = 0, cy = 0; + quad.charge = 0; + if (!quad.leaf) { + var nodes = quad.nodes, n = nodes.length, i = -1, c; + while (++i < n) { + c = nodes[i]; + if (c == null) continue; + d3_layout_forceAccumulate(c, alpha, charges); + quad.charge += c.charge; + cx += c.charge * c.cx; + cy += c.charge * c.cy; + } + } + if (quad.point) { + if (!quad.leaf) { + quad.point.x += Math.random() - .5; + quad.point.y += Math.random() - .5; + } + var k = alpha * charges[quad.point.index]; + quad.charge += quad.pointCharge = k; + cx += k * quad.point.x; + cy += k * quad.point.y; + } + quad.cx = cx / quad.charge; + quad.cy = cy / quad.charge; + } + var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity; + d3.layout.hierarchy = function() { + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; + function hierarchy(root) { + var stack = [ root ], nodes = [], node; + root.depth = 0; + while ((node = stack.pop()) != null) { + nodes.push(node); + if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) { + var n, childs, child; + while (--n >= 0) { + stack.push(child = childs[n]); + child.parent = node; + child.depth = node.depth + 1; + } + if (value) node.value = 0; + node.children = childs; + } else { + if (value) node.value = +value.call(hierarchy, node, node.depth) || 0; + delete node.children; + } + } + d3_layout_hierarchyVisitAfter(root, function(node) { + var childs, parent; + if (sort && (childs = node.children)) childs.sort(sort); + if (value && (parent = node.parent)) parent.value += node.value; + }); + return nodes; + } + hierarchy.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return hierarchy; + }; + hierarchy.children = function(x) { + if (!arguments.length) return children; + children = x; + return hierarchy; + }; + hierarchy.value = function(x) { + if (!arguments.length) return value; + value = x; + return hierarchy; + }; + hierarchy.revalue = function(root) { + if (value) { + d3_layout_hierarchyVisitBefore(root, function(node) { + if (node.children) node.value = 0; + }); + d3_layout_hierarchyVisitAfter(root, function(node) { + var parent; + if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0; + if (parent = node.parent) parent.value += node.value; + }); + } + return root; + }; + return hierarchy; + }; + function d3_layout_hierarchyRebind(object, hierarchy) { + d3.rebind(object, hierarchy, "sort", "children", "value"); + object.nodes = object; + object.links = d3_layout_hierarchyLinks; + return object; + } + function d3_layout_hierarchyVisitBefore(node, callback) { + var nodes = [ node ]; + while ((node = nodes.pop()) != null) { + callback(node); + if ((children = node.children) && (n = children.length)) { + var n, children; + while (--n >= 0) nodes.push(children[n]); + } + } + } + function d3_layout_hierarchyVisitAfter(node, callback) { + var nodes = [ node ], nodes2 = []; + while ((node = nodes.pop()) != null) { + nodes2.push(node); + if ((children = node.children) && (n = children.length)) { + var i = -1, n, children; + while (++i < n) nodes.push(children[i]); + } + } + while ((node = nodes2.pop()) != null) { + callback(node); + } + } + function d3_layout_hierarchyChildren(d) { + return d.children; + } + function d3_layout_hierarchyValue(d) { + return d.value; + } + function d3_layout_hierarchySort(a, b) { + return b.value - a.value; + } + function d3_layout_hierarchyLinks(nodes) { + return d3.merge(nodes.map(function(parent) { + return (parent.children || []).map(function(child) { + return { + source: parent, + target: child + }; + }); + })); + } + d3.layout.partition = function() { + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; + function position(node, x, dx, dy) { + var children = node.children; + node.x = x; + node.y = node.depth * dy; + node.dx = dx; + node.dy = dy; + if (children && (n = children.length)) { + var i = -1, n, c, d; + dx = node.value ? dx / node.value : 0; + while (++i < n) { + position(c = children[i], x, d = c.value * dx, dy); + x += d; + } + } + } + function depth(node) { + var children = node.children, d = 0; + if (children && (n = children.length)) { + var i = -1, n; + while (++i < n) d = Math.max(d, depth(children[i])); + } + return 1 + d; + } + function partition(d, i) { + var nodes = hierarchy.call(this, d, i); + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); + return nodes; + } + partition.size = function(x) { + if (!arguments.length) return size; + size = x; + return partition; + }; + return d3_layout_hierarchyRebind(partition, hierarchy); + }; + d3.layout.pie = function() { + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ, padAngle = 0; + function pie(data) { + var n = data.length, values = data.map(function(d, i) { + return +value.call(pie, d, i); + }), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), k = (da - n * pa) / d3.sum(values), index = d3.range(n), arcs = [], v; + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { + return values[j] - values[i]; + } : function(i, j) { + return sort(data[i], data[j]); + }); + index.forEach(function(i) { + arcs[i] = { + data: data[i], + value: v = values[i], + startAngle: a, + endAngle: a += v * k + pa, + padAngle: p + }; + }); + return arcs; + } + pie.value = function(_) { + if (!arguments.length) return value; + value = _; + return pie; + }; + pie.sort = function(_) { + if (!arguments.length) return sort; + sort = _; + return pie; + }; + pie.startAngle = function(_) { + if (!arguments.length) return startAngle; + startAngle = _; + return pie; + }; + pie.endAngle = function(_) { + if (!arguments.length) return endAngle; + endAngle = _; + return pie; + }; + pie.padAngle = function(_) { + if (!arguments.length) return padAngle; + padAngle = _; + return pie; + }; + return pie; + }; + var d3_layout_pieSortByValue = {}; + d3.layout.stack = function() { + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + function stack(data, index) { + if (!(n = data.length)) return data; + var series = data.map(function(d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function(d) { + return d.map(function(v, i) { + return [ x.call(stack, v, i), y.call(stack, v, i) ]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var m = series[0].length, n, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + stack.values = function(x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function(x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function(x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function(z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function(z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function(z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + }; + function d3_layout_stackX(d) { + return d.x; + } + function d3_layout_stackY(d) { + return d.y; + } + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + var d3_layout_stackOrders = d3.map({ + "inside-out": function(data) { + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { + return max[a] - max[b]; + }), top = 0, bottom = 0, tops = [], bottoms = []; + for (i = 0; i < n; ++i) { + j = index[i]; + if (top < bottom) { + top += sums[j]; + tops.push(j); + } else { + bottom += sums[j]; + bottoms.push(j); + } + } + return bottoms.reverse().concat(tops); + }, + reverse: function(data) { + return d3.range(data.length).reverse(); + }, + "default": d3_layout_stackOrderDefault + }); + var d3_layout_stackOffsets = d3.map({ + silhouette: function(data) { + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o > max) max = o; + sums.push(o); + } + for (j = 0; j < m; ++j) { + y0[j] = (max - sums[j]) / 2; + } + return y0; + }, + wiggle: function(data) { + var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; + y0[0] = o = o0 = 0; + for (j = 1; j < m; ++j) { + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; + } + s2 += s3 * data[i][j][1]; + } + y0[j] = o -= s1 ? s2 / s1 * dx : 0; + if (o < o0) o0 = o; + } + for (j = 0; j < m; ++j) y0[j] -= o0; + return y0; + }, + expand: function(data) { + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; + } + for (j = 0; j < m; ++j) y0[j] = 0; + return y0; + }, + zero: d3_layout_stackOffsetZero + }); + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + function d3_layout_stackMaxIndex(array) { + var i = 1, j = 0, v = array[0][1], k, n = array.length; + for (;i < n; ++i) { + if ((k = array[i][1]) > v) { + j = i; + v = k; + } + } + return j; + } + function d3_layout_stackReduceSum(d) { + return d.reduce(d3_layout_stackSum, 0); + } + function d3_layout_stackSum(p, d) { + return p + d[1]; + } + d3.layout.histogram = function() { + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; + function histogram(data, i) { + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; + while (++i < m) { + bin = bins[i] = []; + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); + bin.y = 0; + } + if (m > 0) { + i = -1; + while (++i < n) { + x = values[i]; + if (x >= range[0] && x <= range[1]) { + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; + bin.y += k; + bin.push(data[i]); + } + } + } + return bins; + } + histogram.value = function(x) { + if (!arguments.length) return valuer; + valuer = x; + return histogram; + }; + histogram.range = function(x) { + if (!arguments.length) return ranger; + ranger = d3_functor(x); + return histogram; + }; + histogram.bins = function(x) { + if (!arguments.length) return binner; + binner = typeof x === "number" ? function(range) { + return d3_layout_histogramBinFixed(range, x); + } : d3_functor(x); + return histogram; + }; + histogram.frequency = function(x) { + if (!arguments.length) return frequency; + frequency = !!x; + return histogram; + }; + return histogram; + }; + function d3_layout_histogramBinSturges(range, values) { + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); + } + function d3_layout_histogramBinFixed(range, n) { + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; + while (++x <= n) f[x] = m * x + b; + return f; + } + function d3_layout_histogramRange(values) { + return [ d3.min(values), d3.max(values) ]; + } + d3.layout.pack = function() { + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; + function pack(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { + return radius; + }; + root.x = root.y = 0; + d3_layout_hierarchyVisitAfter(root, function(d) { + d.r = +r(d.value); + }); + d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings); + if (padding) { + var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; + d3_layout_hierarchyVisitAfter(root, function(d) { + d.r += dr; + }); + d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings); + d3_layout_hierarchyVisitAfter(root, function(d) { + d.r -= dr; + }); + } + d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); + return nodes; + } + pack.size = function(_) { + if (!arguments.length) return size; + size = _; + return pack; + }; + pack.radius = function(_) { + if (!arguments.length) return radius; + radius = _ == null || typeof _ === "function" ? _ : +_; + return pack; + }; + pack.padding = function(_) { + if (!arguments.length) return padding; + padding = +_; + return pack; + }; + return d3_layout_hierarchyRebind(pack, hierarchy); + }; + function d3_layout_packSort(a, b) { + return a.value - b.value; + } + function d3_layout_packInsert(a, b) { + var c = a._pack_next; + a._pack_next = b; + b._pack_prev = a; + b._pack_next = c; + c._pack_prev = b; + } + function d3_layout_packSplice(a, b) { + a._pack_next = b; + b._pack_prev = a; + } + function d3_layout_packIntersects(a, b) { + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; + return .999 * dr * dr > dx * dx + dy * dy; + } + function d3_layout_packSiblings(node) { + if (!(nodes = node.children) || !(n = nodes.length)) return; + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; + function bound(node) { + xMin = Math.min(node.x - node.r, xMin); + xMax = Math.max(node.x + node.r, xMax); + yMin = Math.min(node.y - node.r, yMin); + yMax = Math.max(node.y + node.r, yMax); + } + nodes.forEach(d3_layout_packLink); + a = nodes[0]; + a.x = -a.r; + a.y = 0; + bound(a); + if (n > 1) { + b = nodes[1]; + b.x = b.r; + b.y = 0; + bound(b); + if (n > 2) { + c = nodes[2]; + d3_layout_packPlace(a, b, c); + bound(c); + d3_layout_packInsert(a, c); + a._pack_prev = c; + d3_layout_packInsert(c, b); + b = a._pack_next; + for (i = 3; i < n; i++) { + d3_layout_packPlace(a, b, c = nodes[i]); + var isect = 0, s1 = 1, s2 = 1; + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { + if (d3_layout_packIntersects(j, c)) { + isect = 1; + break; + } + } + if (isect == 1) { + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { + if (d3_layout_packIntersects(k, c)) { + break; + } + } + } + if (isect) { + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); + i--; + } else { + d3_layout_packInsert(a, c); + b = c; + bound(c); + } + } + } + } + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; + for (i = 0; i < n; i++) { + c = nodes[i]; + c.x -= cx; + c.y -= cy; + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); + } + node.r = cr; + nodes.forEach(d3_layout_packUnlink); + } + function d3_layout_packLink(node) { + node._pack_next = node._pack_prev = node; + } + function d3_layout_packUnlink(node) { + delete node._pack_next; + delete node._pack_prev; + } + function d3_layout_packTransform(node, x, y, k) { + var children = node.children; + node.x = x += k * node.x; + node.y = y += k * node.y; + node.r *= k; + if (children) { + var i = -1, n = children.length; + while (++i < n) d3_layout_packTransform(children[i], x, y, k); + } + } + function d3_layout_packPlace(a, b, c) { + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; + if (db && (dx || dy)) { + var da = b.r + c.r, dc = dx * dx + dy * dy; + da *= da; + db *= db; + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); + c.x = a.x + x * dx + y * dy; + c.y = a.y + x * dy - y * dx; + } else { + c.x = a.x + db; + c.y = a.y; + } + } + d3.layout.tree = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null; + function tree(d, i) { + var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0); + d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z; + d3_layout_hierarchyVisitBefore(root1, secondWalk); + if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else { + var left = root0, right = root0, bottom = root0; + d3_layout_hierarchyVisitBefore(root0, function(node) { + if (node.x < left.x) left = node; + if (node.x > right.x) right = node; + if (node.depth > bottom.depth) bottom = node; + }); + var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1); + d3_layout_hierarchyVisitBefore(root0, function(node) { + node.x = (node.x + tx) * kx; + node.y = node.depth * ky; + }); + } + return nodes; + } + function wrapTree(root0) { + var root1 = { + A: null, + children: [ root0 ] + }, queue = [ root1 ], node1; + while ((node1 = queue.pop()) != null) { + for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) { + queue.push((children[i] = child = { + _: children[i], + parent: node1, + children: (child = children[i].children) && child.slice() || [], + A: null, + a: null, + z: 0, + m: 0, + c: 0, + s: 0, + t: null, + i: i + }).a = child); + } + } + return root1.children[0]; + } + function firstWalk(v) { + var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null; + if (children.length) { + d3_layout_treeShift(v); + var midpoint = (children[0].z + children[children.length - 1].z) / 2; + if (w) { + v.z = w.z + separation(v._, w._); + v.m = v.z - midpoint; + } else { + v.z = midpoint; + } + } else if (w) { + v.z = w.z + separation(v._, w._); + } + v.parent.A = apportion(v, w, v.parent.A || siblings[0]); + } + function secondWalk(v) { + v._.x = v.z + v.parent.m; + v.m += v.parent.m; + } + function apportion(v, w, ancestor) { + if (w) { + var vip = v, vop = v, vim = w, vom = vip.parent.children[0], sip = vip.m, sop = vop.m, sim = vim.m, som = vom.m, shift; + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { + vom = d3_layout_treeLeft(vom); + vop = d3_layout_treeRight(vop); + vop.a = v; + shift = vim.z + sim - vip.z - sip + separation(vim._, vip._); + if (shift > 0) { + d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift); + sip += shift; + sop += shift; + } + sim += vim.m; + sip += vip.m; + som += vom.m; + sop += vop.m; + } + if (vim && !d3_layout_treeRight(vop)) { + vop.t = vim; + vop.m += sim - sop; + } + if (vip && !d3_layout_treeLeft(vom)) { + vom.t = vip; + vom.m += sip - som; + ancestor = v; + } + } + return ancestor; + } + function sizeNode(node) { + node.x *= size[0]; + node.y = node.depth * size[1]; + } + tree.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return tree; + }; + tree.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null ? sizeNode : null; + return tree; + }; + tree.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) == null ? null : sizeNode; + return tree; + }; + return d3_layout_hierarchyRebind(tree, hierarchy); + }; + function d3_layout_treeSeparation(a, b) { + return a.parent == b.parent ? 1 : 2; + } + function d3_layout_treeLeft(v) { + var children = v.children; + return children.length ? children[0] : v.t; + } + function d3_layout_treeRight(v) { + var children = v.children, n; + return (n = children.length) ? children[n - 1] : v.t; + } + function d3_layout_treeMove(wm, wp, shift) { + var change = shift / (wp.i - wm.i); + wp.c -= change; + wp.s += shift; + wm.c += change; + wp.z += shift; + wp.m += shift; + } + function d3_layout_treeShift(v) { + var shift = 0, change = 0, children = v.children, i = children.length, w; + while (--i >= 0) { + w = children[i]; + w.z += shift; + w.m += shift; + shift += w.s + (change += w.c); + } + } + function d3_layout_treeAncestor(vim, v, ancestor) { + return vim.a.parent === v.parent ? vim.a : ancestor; + } + d3.layout.cluster = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function cluster(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; + d3_layout_hierarchyVisitAfter(root, function(node) { + var children = node.children; + if (children && children.length) { + node.x = d3_layout_clusterX(children); + node.y = d3_layout_clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; + d3_layout_hierarchyVisitAfter(root, nodeSize ? function(node) { + node.x = (node.x - root.x) * size[0]; + node.y = (root.y - node.y) * size[1]; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + }); + return nodes; + } + cluster.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return cluster; + }; + cluster.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return cluster; + }; + cluster.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return cluster; + }; + return d3_layout_hierarchyRebind(cluster, hierarchy); + }; + function d3_layout_clusterY(children) { + return 1 + d3.max(children, function(child) { + return child.y; + }); + } + function d3_layout_clusterX(children) { + return children.reduce(function(x, child) { + return x + child.x; + }, 0) / children.length; + } + function d3_layout_clusterLeft(node) { + var children = node.children; + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; + } + function d3_layout_clusterRight(node) { + var children = node.children, n; + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; + } + d3.layout.treemap = function() { + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); + function scale(children, k) { + var i = -1, n = children.length, child, area; + while (++i < n) { + area = (child = children[i]).value * (k < 0 ? 0 : k); + child.area = isNaN(area) || area <= 0 ? 0 : area; + } + } + function squarify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while ((n = remaining.length) > 0) { + row.push(child = remaining[n - 1]); + row.area += child.area; + if (mode !== "squarify" || (score = worst(row, u)) <= best) { + remaining.pop(); + best = score; + } else { + row.area -= row.pop().area; + position(row, u, rect, false); + u = Math.min(rect.dx, rect.dy); + row.length = row.area = 0; + best = Infinity; + } + } + if (row.length) { + position(row, u, rect, true); + row.length = row.area = 0; + } + children.forEach(squarify); + } + } + function stickify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), remaining = children.slice(), child, row = []; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while (child = remaining.pop()) { + row.push(child); + row.area += child.area; + if (child.z != null) { + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); + row.length = row.area = 0; + } + } + children.forEach(stickify); + } + } + function worst(row, u) { + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; + while (++i < n) { + if (!(r = row[i].area)) continue; + if (r < rmin) rmin = r; + if (r > rmax) rmax = r; + } + s *= s; + u *= u; + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; + } + function position(row, u, rect, flush) { + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; + if (u == rect.dx) { + if (flush || v > rect.dy) v = rect.dy; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dy = v; + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); + } + o.z = true; + o.dx += rect.x + rect.dx - x; + rect.y += v; + rect.dy -= v; + } else { + if (flush || v > rect.dx) v = rect.dx; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dx = v; + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); + } + o.z = false; + o.dy += rect.y + rect.dy - y; + rect.x += v; + rect.dx -= v; + } + } + function treemap(d) { + var nodes = stickies || hierarchy(d), root = nodes[0]; + root.x = 0; + root.y = 0; + root.dx = size[0]; + root.dy = size[1]; + if (stickies) hierarchy.revalue(root); + scale([ root ], root.dx * root.dy / root.value); + (stickies ? stickify : squarify)(root); + if (sticky) stickies = nodes; + return nodes; + } + treemap.size = function(x) { + if (!arguments.length) return size; + size = x; + return treemap; + }; + treemap.padding = function(x) { + if (!arguments.length) return padding; + function padFunction(node) { + var p = x.call(treemap, node, node.depth); + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); + } + function padConstant(node) { + return d3_layout_treemapPad(node, x); + } + var type; + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], + padConstant) : padConstant; + return treemap; + }; + treemap.round = function(x) { + if (!arguments.length) return round != Number; + round = x ? Math.round : Number; + return treemap; + }; + treemap.sticky = function(x) { + if (!arguments.length) return sticky; + sticky = x; + stickies = null; + return treemap; + }; + treemap.ratio = function(x) { + if (!arguments.length) return ratio; + ratio = x; + return treemap; + }; + treemap.mode = function(x) { + if (!arguments.length) return mode; + mode = x + ""; + return treemap; + }; + return d3_layout_hierarchyRebind(treemap, hierarchy); + }; + function d3_layout_treemapPadNull(node) { + return { + x: node.x, + y: node.y, + dx: node.dx, + dy: node.dy + }; + } + function d3_layout_treemapPad(node, padding) { + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; + if (dx < 0) { + x += dx / 2; + dx = 0; + } + if (dy < 0) { + y += dy / 2; + dy = 0; + } + return { + x: x, + y: y, + dx: dx, + dy: dy + }; + } + d3.random = { + normal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + return function() { + var x, y, r; + do { + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); + }; + }, + logNormal: function() { + var random = d3.random.normal.apply(d3, arguments); + return function() { + return Math.exp(random()); + }; + }, + bates: function(m) { + var random = d3.random.irwinHall(m); + return function() { + return random() / m; + }; + }, + irwinHall: function(m) { + return function() { + for (var s = 0, j = 0; j < m; j++) s += Math.random(); + return s; + }; + } + }; + d3.scale = {}; + function d3_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_scaleRange(scale) { + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); + } + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); + return function(x) { + return i(u(x)); + }; + } + function d3_scale_nice(domain, nice) { + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; + if (x1 < x0) { + dx = i0, i0 = i1, i1 = dx; + dx = x0, x0 = x1, x1 = dx; + } + domain[i0] = nice.floor(x0); + domain[i1] = nice.ceil(x1); + return domain; + } + function d3_scale_niceStep(step) { + return step ? { + floor: function(x) { + return Math.floor(x / step) * step; + }, + ceil: function(x) { + return Math.ceil(x / step) * step; + } + } : d3_scale_niceIdentity; + } + var d3_scale_niceIdentity = { + floor: d3_identity, + ceil: d3_identity + }; + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; + if (domain[k] < domain[0]) { + domain = domain.slice().reverse(); + range = range.slice().reverse(); + } + while (++j <= k) { + u.push(uninterpolate(domain[j - 1], domain[j])); + i.push(interpolate(range[j - 1], range[j])); + } + return function(x) { + var j = d3.bisect(domain, x, 1, k) - 1; + return i[j](u[j](x)); + }; + } + d3.scale.linear = function() { + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); + }; + function d3_scale_linear(domain, range, interpolate, clamp) { + var output, input; + function rescale() { + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; + output = linear(domain, range, uninterpolate, interpolate); + input = linear(range, domain, uninterpolate, d3_interpolate); + return scale; + } + function scale(x) { + return output(x); + } + scale.invert = function(y) { + return input(y); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(Number); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.rangeRound = function(x) { + return scale.range(x).interpolate(d3_interpolateRound); + }; + scale.clamp = function(x) { + if (!arguments.length) return clamp; + clamp = x; + return rescale(); + }; + scale.interpolate = function(x) { + if (!arguments.length) return interpolate; + interpolate = x; + return rescale(); + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + d3_scale_linearNice(domain, m); + return rescale(); + }; + scale.copy = function() { + return d3_scale_linear(domain, range, interpolate, clamp); + }; + return rescale(); + } + function d3_scale_linearRebind(scale, linear) { + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_scale_linearNice(domain, m) { + return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); + } + function d3_scale_linearTickRange(domain, m) { + if (m == null) m = 10; + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; + extent[0] = Math.ceil(extent[0] / step) * step; + extent[1] = Math.floor(extent[1] / step) * step + step * .5; + extent[2] = step; + return extent; + } + function d3_scale_linearTicks(domain, m) { + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); + } + function d3_scale_linearTickFormat(domain, m, format) { + var range = d3_scale_linearTickRange(domain, m); + if (format) { + var match = d3_format_re.exec(format); + match.shift(); + if (match[8] === "s") { + var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1]))); + if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2])); + match[8] = "f"; + format = d3.format(match.join("")); + return function(d) { + return format(prefix.scale(d)) + prefix.symbol; + }; + } + if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range); + format = match.join(""); + } else { + format = ",." + d3_scale_linearPrecision(range[2]) + "f"; + } + return d3.format(format); + } + var d3_scale_linearFormatSignificant = { + s: 1, + g: 1, + p: 1, + r: 1, + e: 1 + }; + function d3_scale_linearPrecision(value) { + return -Math.floor(Math.log(value) / Math.LN10 + .01); + } + function d3_scale_linearFormatPrecision(type, range) { + var p = d3_scale_linearPrecision(range[2]); + return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2; + } + d3.scale.log = function() { + return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); + }; + function d3_scale_log(linear, base, positive, domain) { + function log(x) { + return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); + } + function pow(x) { + return positive ? Math.pow(base, x) : -Math.pow(base, -x); + } + function scale(x) { + return linear(log(x)); + } + scale.invert = function(x) { + return pow(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + positive = x[0] >= 0; + linear.domain((domain = x.map(Number)).map(log)); + return scale; + }; + scale.base = function(_) { + if (!arguments.length) return base; + base = +_; + linear.domain(domain.map(log)); + return scale; + }; + scale.nice = function() { + var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); + linear.domain(niced); + domain = niced.map(pow); + return scale; + }; + scale.ticks = function() { + var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; + if (isFinite(j - i)) { + if (positive) { + for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); + ticks.push(pow(i)); + } else { + ticks.push(pow(i)); + for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); + } + for (i = 0; ticks[i] < u; i++) {} + for (j = ticks.length; ticks[j - 1] > v; j--) {} + ticks = ticks.slice(i, j); + } + return ticks; + }; + scale.tickFormat = function(n, format) { + if (!arguments.length) return d3_scale_logFormat; + if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); + var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, + Math.floor), e; + return function(d) { + return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + }; + }; + scale.copy = function() { + return d3_scale_log(linear.copy(), base, positive, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { + floor: function(x) { + return -Math.ceil(-x); + }, + ceil: function(x) { + return -Math.floor(-x); + } + }; + d3.scale.pow = function() { + return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); + }; + function d3_scale_pow(linear, exponent, domain) { + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); + function scale(x) { + return linear(powp(x)); + } + scale.invert = function(x) { + return powb(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + linear.domain((domain = x.map(Number)).map(powp)); + return scale; + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + return scale.domain(d3_scale_linearNice(domain, m)); + }; + scale.exponent = function(x) { + if (!arguments.length) return exponent; + powp = d3_scale_powPow(exponent = x); + powb = d3_scale_powPow(1 / exponent); + linear.domain(domain.map(powp)); + return scale; + }; + scale.copy = function() { + return d3_scale_pow(linear.copy(), exponent, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_powPow(e) { + return function(x) { + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); + }; + } + d3.scale.sqrt = function() { + return d3.scale.pow().exponent(.5); + }; + d3.scale.ordinal = function() { + return d3_scale_ordinal([], { + t: "range", + a: [ [] ] + }); + }; + function d3_scale_ordinal(domain, ranger) { + var index, range, rangeBand; + function scale(x) { + return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length]; + } + function steps(start, step) { + return d3.range(domain.length).map(function(i) { + return start + step * i; + }); + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = []; + index = new d3_Map(); + var i = -1, n = x.length, xi; + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); + return scale[ranger.t].apply(scale, ranger.a); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + rangeBand = 0; + ranger = { + t: "range", + a: arguments + }; + return scale; + }; + scale.rangePoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2, + 0) : (stop - start) / (domain.length - 1 + padding); + range = steps(start + step * padding / 2, step); + rangeBand = 0; + ranger = { + t: "rangePoints", + a: arguments + }; + return scale; + }; + scale.rangeRoundPoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2), + 0) : (stop - start) / (domain.length - 1 + padding) | 0; + range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step); + rangeBand = 0; + ranger = { + t: "rangeRoundPoints", + a: arguments + }; + return scale; + }; + scale.rangeBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); + range = steps(start + step * outerPadding, step); + if (reverse) range.reverse(); + rangeBand = step * (1 - padding); + ranger = { + t: "rangeBands", + a: arguments + }; + return scale; + }; + scale.rangeRoundBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)); + range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step); + if (reverse) range.reverse(); + rangeBand = Math.round(step * (1 - padding)); + ranger = { + t: "rangeRoundBands", + a: arguments + }; + return scale; + }; + scale.rangeBand = function() { + return rangeBand; + }; + scale.rangeExtent = function() { + return d3_scaleExtent(ranger.a[0]); + }; + scale.copy = function() { + return d3_scale_ordinal(domain, ranger); + }; + return scale.domain(domain); + } + d3.scale.category10 = function() { + return d3.scale.ordinal().range(d3_category10); + }; + d3.scale.category20 = function() { + return d3.scale.ordinal().range(d3_category20); + }; + d3.scale.category20b = function() { + return d3.scale.ordinal().range(d3_category20b); + }; + d3.scale.category20c = function() { + return d3.scale.ordinal().range(d3_category20c); + }; + var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); + var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); + var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); + var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); + d3.scale.quantile = function() { + return d3_scale_quantile([], []); + }; + function d3_scale_quantile(domain, range) { + var thresholds; + function rescale() { + var k = 0, q = range.length; + thresholds = []; + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); + return scale; + } + function scale(x) { + if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.quantiles = function() { + return thresholds; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; + }; + scale.copy = function() { + return d3_scale_quantile(domain, range); + }; + return rescale(); + } + d3.scale.quantize = function() { + return d3_scale_quantize(0, 1, [ 0, 1 ]); + }; + function d3_scale_quantize(x0, x1, range) { + var kx, i; + function scale(x) { + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; + } + function rescale() { + kx = range.length / (x1 - x0); + i = range.length - 1; + return scale; + } + scale.domain = function(x) { + if (!arguments.length) return [ x0, x1 ]; + x0 = +x[0]; + x1 = +x[x.length - 1]; + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + y = y < 0 ? NaN : y / kx + x0; + return [ y, y + 1 / kx ]; + }; + scale.copy = function() { + return d3_scale_quantize(x0, x1, range); + }; + return rescale(); + } + d3.scale.threshold = function() { + return d3_scale_threshold([ .5 ], [ 0, 1 ]); + }; + function d3_scale_threshold(domain, range) { + function scale(x) { + if (x <= x) return range[d3.bisect(domain, x)]; + } + scale.domain = function(_) { + if (!arguments.length) return domain; + domain = _; + return scale; + }; + scale.range = function(_) { + if (!arguments.length) return range; + range = _; + return scale; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return [ domain[y - 1], domain[y] ]; + }; + scale.copy = function() { + return d3_scale_threshold(domain, range); + }; + return scale; + } + d3.scale.identity = function() { + return d3_scale_identity([ 0, 1 ]); + }; + function d3_scale_identity(domain) { + function identity(x) { + return +x; + } + identity.invert = identity; + identity.domain = identity.range = function(x) { + if (!arguments.length) return domain; + domain = x.map(identity); + return identity; + }; + identity.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + identity.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + identity.copy = function() { + return d3_scale_identity(domain); + }; + return identity; + } + d3.svg = {}; + function d3_zero() { + return 0; + } + d3.svg.arc = function() { + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, padRadius = d3_svg_arcAuto, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle; + function arc() { + var r0 = Math.max(0, +innerRadius.apply(this, arguments)), r1 = Math.max(0, +outerRadius.apply(this, arguments)), a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), cw = a0 > a1 ? 0 : 1; + if (r1 < r0) rc = r1, r1 = r0, r0 = rc; + if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : "") + "Z"; + var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = []; + if (ap = (+padAngle.apply(this, arguments) || 0) / 2) { + rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments); + if (!cw) p1 *= -1; + if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap)); + if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap)); + } + if (r1) { + x0 = r1 * Math.cos(a0 + p1); + y0 = r1 * Math.sin(a0 + p1); + x1 = r1 * Math.cos(a1 - p1); + y1 = r1 * Math.sin(a1 - p1); + var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1; + if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) { + var h1 = (a0 + a1) / 2; + x0 = r1 * Math.cos(h1); + y0 = r1 * Math.sin(h1); + x1 = y1 = null; + } + } else { + x0 = y0 = 0; + } + if (r0) { + x2 = r0 * Math.cos(a1 - p0); + y2 = r0 * Math.sin(a1 - p0); + x3 = r0 * Math.cos(a0 + p0); + y3 = r0 * Math.sin(a0 + p0); + var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1; + if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) { + var h0 = (a0 + a1) / 2; + x2 = r0 * Math.cos(h0); + y2 = r0 * Math.sin(h0); + x3 = y3 = null; + } + } else { + x2 = y2 = 0; + } + if ((rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) { + cr = r0 < r1 ^ cw ? 0 : 1; + var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]); + if (x1 != null) { + var rc1 = Math.min(rc, (r1 - lc) / (kc + 1)), t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw); + if (rc === rc1) { + path.push("M", t30[0], "A", rc1, ",", rc1, " 0 0,", cr, " ", t30[1], "A", r1, ",", r1, " 0 ", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), ",", cw, " ", t12[1], "A", rc1, ",", rc1, " 0 0,", cr, " ", t12[0]); + } else { + path.push("M", t30[0], "A", rc1, ",", rc1, " 0 1,", cr, " ", t12[0]); + } + } else { + path.push("M", x0, ",", y0); + } + if (x3 != null) { + var rc0 = Math.min(rc, (r0 - lc) / (kc - 1)), t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw); + if (rc === rc0) { + path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t21[1], "A", r0, ",", r0, " 0 ", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), ",", 1 - cw, " ", t03[1], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]); + } else { + path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]); + } + } else { + path.push("L", x2, ",", y2); + } + } else { + path.push("M", x0, ",", y0); + if (x1 != null) path.push("A", r1, ",", r1, " 0 ", l1, ",", cw, " ", x1, ",", y1); + path.push("L", x2, ",", y2); + if (x3 != null) path.push("A", r0, ",", r0, " 0 ", l0, ",", 1 - cw, " ", x3, ",", y3); + } + path.push("Z"); + return path.join(""); + } + function circleSegment(r1, cw) { + return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1; + } + arc.innerRadius = function(v) { + if (!arguments.length) return innerRadius; + innerRadius = d3_functor(v); + return arc; + }; + arc.outerRadius = function(v) { + if (!arguments.length) return outerRadius; + outerRadius = d3_functor(v); + return arc; + }; + arc.cornerRadius = function(v) { + if (!arguments.length) return cornerRadius; + cornerRadius = d3_functor(v); + return arc; + }; + arc.padRadius = function(v) { + if (!arguments.length) return padRadius; + padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : d3_functor(v); + return arc; + }; + arc.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return arc; + }; + arc.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return arc; + }; + arc.padAngle = function(v) { + if (!arguments.length) return padAngle; + padAngle = d3_functor(v); + return arc; + }; + arc.centroid = function() { + var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - halfπ; + return [ Math.cos(a) * r, Math.sin(a) * r ]; + }; + return arc; + }; + var d3_svg_arcAuto = "auto"; + function d3_svg_arcInnerRadius(d) { + return d.innerRadius; + } + function d3_svg_arcOuterRadius(d) { + return d.outerRadius; + } + function d3_svg_arcStartAngle(d) { + return d.startAngle; + } + function d3_svg_arcEndAngle(d) { + return d.endAngle; + } + function d3_svg_arcPadAngle(d) { + return d && d.padAngle; + } + function d3_svg_arcSweep(x0, y0, x1, y1) { + return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1; + } + function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) { + var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(r * r * d2 - D * D), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3; + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1; + return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ]; + } + function d3_svg_line(projection) { + var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; + function line(data) { + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); + function segment() { + segments.push("M", interpolate(projection(points), tension)); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); + } else if (points.length) { + segment(); + points = []; + } + } + if (points.length) segment(); + return segments.length ? segments.join("") : null; + } + line.x = function(_) { + if (!arguments.length) return x; + x = _; + return line; + }; + line.y = function(_) { + if (!arguments.length) return y; + y = _; + return line; + }; + line.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return line; + }; + line.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + return line; + }; + line.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return line; + }; + return line; + } + d3.svg.line = function() { + return d3_svg_line(d3_identity); + }; + var d3_svg_lineInterpolators = d3.map({ + linear: d3_svg_lineLinear, + "linear-closed": d3_svg_lineLinearClosed, + step: d3_svg_lineStep, + "step-before": d3_svg_lineStepBefore, + "step-after": d3_svg_lineStepAfter, + basis: d3_svg_lineBasis, + "basis-open": d3_svg_lineBasisOpen, + "basis-closed": d3_svg_lineBasisClosed, + bundle: d3_svg_lineBundle, + cardinal: d3_svg_lineCardinal, + "cardinal-open": d3_svg_lineCardinalOpen, + "cardinal-closed": d3_svg_lineCardinalClosed, + monotone: d3_svg_lineMonotone + }); + d3_svg_lineInterpolators.forEach(function(key, value) { + value.key = key; + value.closed = /-closed$/.test(key); + }); + function d3_svg_lineLinear(points) { + return points.join("L"); + } + function d3_svg_lineLinearClosed(points) { + return d3_svg_lineLinear(points) + "Z"; + } + function d3_svg_lineStep(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); + if (n > 1) path.push("H", p[0]); + return path.join(""); + } + function d3_svg_lineStepBefore(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); + return path.join(""); + } + function d3_svg_lineStepAfter(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); + return path.join(""); + } + function d3_svg_lineCardinalOpen(points, tension) { + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineCardinalClosed(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), + points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); + } + function d3_svg_lineCardinal(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineHermite(points, tangents) { + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { + return d3_svg_lineLinear(points); + } + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; + if (quad) { + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; + p0 = points[1]; + pi = 2; + } + if (tangents.length > 1) { + t = tangents[1]; + p = points[pi]; + pi++; + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + for (var i = 2; i < tangents.length; i++, pi++) { + p = points[pi]; + t = tangents[i]; + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + } + } + if (quad) { + var lp = points[pi]; + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; + } + return path; + } + function d3_svg_lineCardinalTangents(points, tension) { + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; + while (++i < n) { + p0 = p1; + p1 = p2; + p2 = points[i]; + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); + } + return tangents; + } + function d3_svg_lineBasis(points) { + if (points.length < 3) return d3_svg_lineLinear(points); + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + points.push(points[n - 1]); + while (++i <= n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + points.pop(); + path.push("L", pi); + return path.join(""); + } + function d3_svg_lineBasisOpen(points) { + if (points.length < 4) return d3_svg_lineLinear(points); + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; + while (++i < 3) { + pi = points[i]; + px.push(pi[0]); + py.push(pi[1]); + } + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); + --i; + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisClosed(points) { + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; + while (++i < 4) { + pi = points[i % n]; + px.push(pi[0]); + py.push(pi[1]); + } + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + --i; + while (++i < m) { + pi = points[i % n]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBundle(points, tension) { + var n = points.length - 1; + if (n) { + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; + while (++i <= n) { + p = points[i]; + t = i / n; + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); + } + } + return d3_svg_lineBasis(points); + } + function d3_svg_lineDot4(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; + function d3_svg_lineBasisBezier(path, x, y) { + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); + } + function d3_svg_lineSlope(p0, p1) { + return (p1[1] - p0[1]) / (p1[0] - p0[0]); + } + function d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function d3_svg_lineMonotoneTangents(points) { + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = d3_svg_lineSlope(points[i], points[i + 1]); + if (abs(d) < ε) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); + tangents.push([ s || 0, m[i] * s || 0 ]); + } + return tangents; + } + function d3_svg_lineMonotone(points) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); + } + d3.svg.line.radial = function() { + var line = d3_svg_line(d3_svg_lineRadial); + line.radius = line.x, delete line.x; + line.angle = line.y, delete line.y; + return line; + }; + function d3_svg_lineRadial(points) { + var point, i = -1, n = points.length, r, a; + while (++i < n) { + point = points[i]; + r = point[0]; + a = point[1] - halfπ; + point[0] = r * Math.cos(a); + point[1] = r * Math.sin(a); + } + return points; + } + function d3_svg_area(projection) { + var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; + function area(data) { + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { + return x; + } : d3_functor(x1), fy1 = y0 === y1 ? function() { + return y; + } : d3_functor(y1), x, y; + function segment() { + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); + } else if (points0.length) { + segment(); + points0 = []; + points1 = []; + } + } + if (points0.length) segment(); + return segments.length ? segments.join("") : null; + } + area.x = function(_) { + if (!arguments.length) return x1; + x0 = x1 = _; + return area; + }; + area.x0 = function(_) { + if (!arguments.length) return x0; + x0 = _; + return area; + }; + area.x1 = function(_) { + if (!arguments.length) return x1; + x1 = _; + return area; + }; + area.y = function(_) { + if (!arguments.length) return y1; + y0 = y1 = _; + return area; + }; + area.y0 = function(_) { + if (!arguments.length) return y0; + y0 = _; + return area; + }; + area.y1 = function(_) { + if (!arguments.length) return y1; + y1 = _; + return area; + }; + area.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return area; + }; + area.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + interpolateReverse = interpolate.reverse || interpolate; + L = interpolate.closed ? "M" : "L"; + return area; + }; + area.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return area; + }; + return area; + } + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; + d3.svg.area = function() { + return d3_svg_area(d3_identity); + }; + d3.svg.area.radial = function() { + var area = d3_svg_area(d3_svg_lineRadial); + area.radius = area.x, delete area.x; + area.innerRadius = area.x0, delete area.x0; + area.outerRadius = area.x1, delete area.x1; + area.angle = area.y, delete area.y; + area.startAngle = area.y0, delete area.y0; + area.endAngle = area.y1, delete area.y1; + return area; + }; + d3.svg.chord = function() { + var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function chord(d, i) { + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; + } + function subgroup(self, f, d, i) { + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) - halfπ, a1 = endAngle.call(self, subgroup, i) - halfπ; + return { + r: r, + a0: a0, + a1: a1, + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] + }; + } + function equals(a, b) { + return a.a0 == b.a0 && a.a1 == b.a1; + } + function arc(r, p, a) { + return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; + } + function curve(r0, p0, r1, p1) { + return "Q 0,0 " + p1; + } + chord.radius = function(v) { + if (!arguments.length) return radius; + radius = d3_functor(v); + return chord; + }; + chord.source = function(v) { + if (!arguments.length) return source; + source = d3_functor(v); + return chord; + }; + chord.target = function(v) { + if (!arguments.length) return target; + target = d3_functor(v); + return chord; + }; + chord.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return chord; + }; + chord.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return chord; + }; + return chord; + }; + function d3_svg_chordRadius(d) { + return d.radius; + } + d3.svg.diagonal = function() { + var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; + function diagonal(d, i) { + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { + x: p0.x, + y: m + }, { + x: p3.x, + y: m + }, p3 ]; + p = p.map(projection); + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; + } + diagonal.source = function(x) { + if (!arguments.length) return source; + source = d3_functor(x); + return diagonal; + }; + diagonal.target = function(x) { + if (!arguments.length) return target; + target = d3_functor(x); + return diagonal; + }; + diagonal.projection = function(x) { + if (!arguments.length) return projection; + projection = x; + return diagonal; + }; + return diagonal; + }; + function d3_svg_diagonalProjection(d) { + return [ d.x, d.y ]; + } + d3.svg.diagonal.radial = function() { + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; + diagonal.projection = function(x) { + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; + }; + return diagonal; + }; + function d3_svg_diagonalRadialProjection(projection) { + return function() { + var d = projection.apply(this, arguments), r = d[0], a = d[1] - halfπ; + return [ r * Math.cos(a), r * Math.sin(a) ]; + }; + } + d3.svg.symbol = function() { + var type = d3_svg_symbolType, size = d3_svg_symbolSize; + function symbol(d, i) { + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); + } + symbol.type = function(x) { + if (!arguments.length) return type; + type = d3_functor(x); + return symbol; + }; + symbol.size = function(x) { + if (!arguments.length) return size; + size = d3_functor(x); + return symbol; + }; + return symbol; + }; + function d3_svg_symbolSize() { + return 64; + } + function d3_svg_symbolType() { + return "circle"; + } + function d3_svg_symbolCircle(size) { + var r = Math.sqrt(size / π); + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; + } + var d3_svg_symbols = d3.map({ + circle: d3_svg_symbolCircle, + cross: function(size) { + var r = Math.sqrt(size / 5) / 2; + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; + }, + diamond: function(size) { + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; + }, + square: function(size) { + var r = Math.sqrt(size) / 2; + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; + }, + "triangle-down": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; + }, + "triangle-up": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; + } + }); + d3.svg.symbolTypes = d3_svg_symbols.keys(); + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); + d3_selectionPrototype.transition = function(name) { + var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || { + time: Date.now(), + ease: d3_ease_cubicInOut, + delay: 0, + duration: 250 + }; + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) d3_transitionNode(node, i, ns, id, transition); + subgroup.push(node); + } + } + return d3_transition(subgroups, ns, id); + }; + d3_selectionPrototype.interrupt = function(name) { + return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name))); + }; + var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace()); + function d3_selection_interruptNS(ns) { + return function() { + var lock, active; + if ((lock = this[ns]) && (active = lock[lock.active])) { + if (--lock.count) { + delete lock[lock.active]; + lock.active += .5; + } else { + delete this[ns]; + } + active.event && active.event.interrupt.call(this, this.__data__, active.index); + } + }; + } + function d3_transition(groups, ns, id) { + d3_subclass(groups, d3_transitionPrototype); + groups.namespace = ns; + groups.id = id; + return groups; + } + var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; + d3_transitionPrototype.call = d3_selectionPrototype.call; + d3_transitionPrototype.empty = d3_selectionPrototype.empty; + d3_transitionPrototype.node = d3_selectionPrototype.node; + d3_transitionPrototype.size = d3_selectionPrototype.size; + d3.transition = function(selection, name) { + return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3_selectionRoot.transition(selection); + }; + d3.transition.prototype = d3_transitionPrototype; + d3_transitionPrototype.select = function(selector) { + var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + d3_transitionNode(subnode, i, ns, id, node[ns][id]); + subgroup.push(subnode); + } else { + subgroup.push(null); + } + } + } + return d3_transition(subgroups, ns, id); + }; + d3_transitionPrototype.selectAll = function(selector) { + var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + transition = node[ns][id]; + subnodes = selector.call(node, node.__data__, i, j); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o; ) { + if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition); + subgroup.push(subnode); + } + } + } + } + return d3_transition(subgroups, ns, id); + }; + d3_transitionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { + subgroup.push(node); + } + } + } + return d3_transition(subgroups, this.namespace, this.id); + }; + d3_transitionPrototype.tween = function(name, tween) { + var id = this.id, ns = this.namespace; + if (arguments.length < 2) return this.node()[ns][id].tween.get(name); + return d3_selection_each(this, tween == null ? function(node) { + node[ns][id].tween.remove(name); + } : function(node) { + node[ns][id].tween.set(name, tween); + }); + }; + function d3_transition_tween(groups, name, value, tween) { + var id = groups.id, ns = groups.namespace; + return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { + node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); + } : (value = tween(value), function(node) { + node[ns][id].tween.set(name, value); + })); + } + d3_transitionPrototype.attr = function(nameNS, value) { + if (arguments.length < 2) { + for (value in nameNS) this.attr(value, nameNS[value]); + return this; + } + var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrTween(b) { + return b == null ? attrNull : (b += "", function() { + var a = this.getAttribute(name), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttribute(name, i(t)); + }); + }); + } + function attrTweenNS(b) { + return b == null ? attrNullNS : (b += "", function() { + var a = this.getAttributeNS(name.space, name.local), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttributeNS(name.space, name.local, i(t)); + }); + }); + } + return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.attrTween = function(nameNS, tween) { + var name = d3.ns.qualify(nameNS); + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f && function(t) { + this.setAttribute(name, f(t)); + }; + } + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f && function(t) { + this.setAttributeNS(name.space, name.local, f(t)); + }; + } + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.style(priority, name[priority], value); + return this; + } + priority = ""; + } + function styleNull() { + this.style.removeProperty(name); + } + function styleString(b) { + return b == null ? styleNull : (b += "", function() { + var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; + return a !== b && (i = d3_interpolate(a, b), function(t) { + this.style.setProperty(name, i(t), priority); + }); + }); + } + return d3_transition_tween(this, "style." + name, value, styleString); + }; + d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + function styleTween(d, i) { + var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); + return f && function(t) { + this.style.setProperty(name, f(t), priority); + }; + } + return this.tween("style." + name, styleTween); + }; + d3_transitionPrototype.text = function(value) { + return d3_transition_tween(this, "text", value, d3_transition_text); + }; + function d3_transition_text(b) { + if (b == null) b = ""; + return function() { + this.textContent = b; + }; + } + d3_transitionPrototype.remove = function() { + var ns = this.namespace; + return this.each("end.transition", function() { + var p; + if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this); + }); + }; + d3_transitionPrototype.ease = function(value) { + var id = this.id, ns = this.namespace; + if (arguments.length < 1) return this.node()[ns][id].ease; + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); + return d3_selection_each(this, function(node) { + node[ns][id].ease = value; + }); + }; + d3_transitionPrototype.delay = function(value) { + var id = this.id, ns = this.namespace; + if (arguments.length < 1) return this.node()[ns][id].delay; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node[ns][id].delay = +value.call(node, node.__data__, i, j); + } : (value = +value, function(node) { + node[ns][id].delay = value; + })); + }; + d3_transitionPrototype.duration = function(value) { + var id = this.id, ns = this.namespace; + if (arguments.length < 1) return this.node()[ns][id].duration; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); + } : (value = Math.max(1, value), function(node) { + node[ns][id].duration = value; + })); + }; + d3_transitionPrototype.each = function(type, listener) { + var id = this.id, ns = this.namespace; + if (arguments.length < 2) { + var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; + try { + d3_transitionInheritId = id; + d3_selection_each(this, function(node, i, j) { + d3_transitionInherit = node[ns][id]; + type.call(node, node.__data__, i, j); + }); + } finally { + d3_transitionInherit = inherit; + d3_transitionInheritId = inheritId; + } + } else { + d3_selection_each(this, function(node) { + var transition = node[ns][id]; + (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener); + }); + } + return this; + }; + d3_transitionPrototype.transition = function() { + var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, subgroups = [], subgroup, group, node, transition; + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if (node = group[i]) { + transition = node[ns][id0]; + d3_transitionNode(node, i, ns, id1, { + time: transition.time, + ease: transition.ease, + delay: transition.delay + transition.duration, + duration: transition.duration + }); + } + subgroup.push(node); + } + } + return d3_transition(subgroups, ns, id1); + }; + function d3_transitionNamespace(name) { + return name == null ? "__transition__" : "__transition_" + name + "__"; + } + function d3_transitionNode(node, i, ns, id, inherit) { + var lock = node[ns] || (node[ns] = { + active: 0, + count: 0 + }), transition = lock[id]; + if (!transition) { + var time = inherit.time; + transition = lock[id] = { + tween: new d3_Map(), + time: time, + delay: inherit.delay, + duration: inherit.duration, + ease: inherit.ease, + index: i + }; + inherit = null; + ++lock.count; + d3.timer(function(elapsed) { + var delay = transition.delay, duration, ease, timer = d3_timer_active, tweened = []; + timer.t = delay + time; + if (delay <= elapsed) return start(elapsed - delay); + timer.c = start; + function start(elapsed) { + if (lock.active > id) return stop(); + var active = lock[lock.active]; + if (active) { + --lock.count; + delete lock[lock.active]; + active.event && active.event.interrupt.call(node, node.__data__, active.index); + } + lock.active = id; + transition.event && transition.event.start.call(node, node.__data__, i); + transition.tween.forEach(function(key, value) { + if (value = value.call(node, node.__data__, i)) { + tweened.push(value); + } + }); + ease = transition.ease; + duration = transition.duration; + d3.timer(function() { + timer.c = tick(elapsed || 1) ? d3_true : tick; + return 1; + }, 0, time); + } + function tick(elapsed) { + if (lock.active !== id) return 1; + var t = elapsed / duration, e = ease(t), n = tweened.length; + while (n > 0) { + tweened[--n].call(node, e); + } + if (t >= 1) { + transition.event && transition.event.end.call(node, node.__data__, i); + return stop(); + } + } + function stop() { + if (--lock.count) delete lock[id]; else delete node[ns]; + return 1; + } + }, 0, time); + } + } + d3.svg.axis = function() { + var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_; + function axis(g) { + g.each(function() { + var g = d3.select(this); + var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy(); + var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickSpacing = Math.max(innerTickSize, 0) + tickPadding, tickTransform; + var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), + d3.transition(path)); + tickEnter.append("line"); + tickEnter.append("text"); + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"), sign = orient === "top" || orient === "left" ? -1 : 1, x1, x2, y1, y2; + if (orient === "bottom" || orient === "top") { + tickTransform = d3_svg_axisX, x1 = "x", y1 = "y", x2 = "x2", y2 = "y2"; + text.attr("dy", sign < 0 ? "0em" : ".71em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize); + } else { + tickTransform = d3_svg_axisY, x1 = "y", y1 = "x", x2 = "y2", y2 = "x2"; + text.attr("dy", ".32em").style("text-anchor", sign < 0 ? "end" : "start"); + pathUpdate.attr("d", "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize); + } + lineEnter.attr(y2, sign * innerTickSize); + textEnter.attr(y1, sign * tickSpacing); + lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize); + textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing); + if (scale1.rangeBand) { + var x = scale1, dx = x.rangeBand() / 2; + scale0 = scale1 = function(d) { + return x(d) + dx; + }; + } else if (scale0.rangeBand) { + scale0 = scale1; + } else { + tickExit.call(tickTransform, scale1, scale0); + } + tickEnter.call(tickTransform, scale0, scale1); + tickUpdate.call(tickTransform, scale1, scale1); + }); + } + axis.scale = function(x) { + if (!arguments.length) return scale; + scale = x; + return axis; + }; + axis.orient = function(x) { + if (!arguments.length) return orient; + orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; + return axis; + }; + axis.ticks = function() { + if (!arguments.length) return tickArguments_; + tickArguments_ = arguments; + return axis; + }; + axis.tickValues = function(x) { + if (!arguments.length) return tickValues; + tickValues = x; + return axis; + }; + axis.tickFormat = function(x) { + if (!arguments.length) return tickFormat_; + tickFormat_ = x; + return axis; + }; + axis.tickSize = function(x) { + var n = arguments.length; + if (!n) return innerTickSize; + innerTickSize = +x; + outerTickSize = +arguments[n - 1]; + return axis; + }; + axis.innerTickSize = function(x) { + if (!arguments.length) return innerTickSize; + innerTickSize = +x; + return axis; + }; + axis.outerTickSize = function(x) { + if (!arguments.length) return outerTickSize; + outerTickSize = +x; + return axis; + }; + axis.tickPadding = function(x) { + if (!arguments.length) return tickPadding; + tickPadding = +x; + return axis; + }; + axis.tickSubdivide = function() { + return arguments.length && axis; + }; + return axis; + }; + var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { + top: 1, + right: 1, + bottom: 1, + left: 1 + }; + function d3_svg_axisX(selection, x0, x1) { + selection.attr("transform", function(d) { + var v0 = x0(d); + return "translate(" + (isFinite(v0) ? v0 : x1(d)) + ",0)"; + }); + } + function d3_svg_axisY(selection, y0, y1) { + selection.attr("transform", function(d) { + var v0 = y0(d); + return "translate(0," + (isFinite(v0) ? v0 : y1(d)) + ")"; + }); + } + d3.svg.brush = function() { + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0]; + function brush(g) { + g.each(function() { + var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); + var background = g.selectAll(".background").data([ 0 ]); + background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); + g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move"); + var resize = g.selectAll(".resize").data(resizes, d3_identity); + resize.exit().remove(); + resize.enter().append("g").attr("class", function(d) { + return "resize " + d; + }).style("cursor", function(d) { + return d3_svg_brushCursor[d]; + }).append("rect").attr("x", function(d) { + return /[ew]$/.test(d) ? -3 : null; + }).attr("y", function(d) { + return /^[ns]/.test(d) ? -3 : null; + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); + resize.style("display", brush.empty() ? "none" : null); + var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range; + if (x) { + range = d3_scaleRange(x); + backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]); + redrawX(gUpdate); + } + if (y) { + range = d3_scaleRange(y); + backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]); + redrawY(gUpdate); + } + redraw(gUpdate); + }); + } + brush.event = function(g) { + g.each(function() { + var event_ = event.of(this, arguments), extent1 = { + x: xExtent, + y: yExtent, + i: xExtentDomain, + j: yExtentDomain + }, extent0 = this.__chart__ || extent1; + this.__chart__ = extent1; + if (d3_transitionInheritId) { + d3.select(this).transition().each("start.brush", function() { + xExtentDomain = extent0.i; + yExtentDomain = extent0.j; + xExtent = extent0.x; + yExtent = extent0.y; + event_({ + type: "brushstart" + }); + }).tween("brush:brush", function() { + var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y); + xExtentDomain = yExtentDomain = null; + return function(t) { + xExtent = extent1.x = xi(t); + yExtent = extent1.y = yi(t); + event_({ + type: "brush", + mode: "resize" + }); + }; + }).each("end.brush", function() { + xExtentDomain = extent1.i; + yExtentDomain = extent1.j; + event_({ + type: "brush", + mode: "resize" + }); + event_({ + type: "brushend" + }); + }); + } else { + event_({ + type: "brushstart" + }); + event_({ + type: "brush", + mode: "resize" + }); + event_({ + type: "brushend" + }); + } + }); + }; + function redraw(g) { + g.selectAll(".resize").attr("transform", function(d) { + return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")"; + }); + } + function redrawX(g) { + g.select(".extent").attr("x", xExtent[0]); + g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]); + } + function redrawY(g) { + g.select(".extent").attr("y", yExtent[0]); + g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]); + } + function brushstart() { + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = d3.mouse(target), offset; + var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); + if (d3.event.changedTouches) { + w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); + } else { + w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); + } + g.interrupt().selectAll("*").interrupt(); + if (dragging) { + origin[0] = xExtent[0] - origin[0]; + origin[1] = yExtent[0] - origin[1]; + } else if (resizing) { + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); + offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ]; + origin[0] = xExtent[ex]; + origin[1] = yExtent[ey]; + } else if (d3.event.altKey) center = origin.slice(); + g.style("pointer-events", "none").selectAll(".resize").style("display", null); + d3.select("body").style("cursor", eventTarget.style("cursor")); + event_({ + type: "brushstart" + }); + brushmove(); + function keydown() { + if (d3.event.keyCode == 32) { + if (!dragging) { + center = null; + origin[0] -= xExtent[1]; + origin[1] -= yExtent[1]; + dragging = 2; + } + d3_eventPreventDefault(); + } + } + function keyup() { + if (d3.event.keyCode == 32 && dragging == 2) { + origin[0] += xExtent[1]; + origin[1] += yExtent[1]; + dragging = 0; + d3_eventPreventDefault(); + } + } + function brushmove() { + var point = d3.mouse(target), moved = false; + if (offset) { + point[0] += offset[0]; + point[1] += offset[1]; + } + if (!dragging) { + if (d3.event.altKey) { + if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ]; + origin[0] = xExtent[+(point[0] < center[0])]; + origin[1] = yExtent[+(point[1] < center[1])]; + } else center = null; + } + if (resizingX && move1(point, x, 0)) { + redrawX(g); + moved = true; + } + if (resizingY && move1(point, y, 1)) { + redrawY(g); + moved = true; + } + if (moved) { + redraw(g); + event_({ + type: "brush", + mode: dragging ? "move" : "resize" + }); + } + } + function move1(point, scale, i) { + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max; + if (dragging) { + r0 -= position; + r1 -= size + position; + } + min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i]; + if (dragging) { + max = (min += position) + size; + } else { + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); + if (position < min) { + max = min; + min = position; + } else { + max = position; + } + } + if (extent[0] != min || extent[1] != max) { + if (i) yExtentDomain = null; else xExtentDomain = null; + extent[0] = min; + extent[1] = max; + return true; + } + } + function brushend() { + brushmove(); + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); + d3.select("body").style("cursor", null); + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); + dragRestore(); + event_({ + type: "brushend" + }); + } + } + brush.x = function(z) { + if (!arguments.length) return x; + x = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.y = function(z) { + if (!arguments.length) return y; + y = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.clamp = function(z) { + if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null; + if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z; + return brush; + }; + brush.extent = function(z) { + var x0, x1, y0, y1, t; + if (!arguments.length) { + if (x) { + if (xExtentDomain) { + x0 = xExtentDomain[0], x1 = xExtentDomain[1]; + } else { + x0 = xExtent[0], x1 = xExtent[1]; + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + } + } + if (y) { + if (yExtentDomain) { + y0 = yExtentDomain[0], y1 = yExtentDomain[1]; + } else { + y0 = yExtent[0], y1 = yExtent[1]; + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + } + } + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; + } + if (x) { + x0 = z[0], x1 = z[1]; + if (y) x0 = x0[0], x1 = x1[0]; + xExtentDomain = [ x0, x1 ]; + if (x.invert) x0 = x(x0), x1 = x(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ]; + } + if (y) { + y0 = z[0], y1 = z[1]; + if (x) y0 = y0[1], y1 = y1[1]; + yExtentDomain = [ y0, y1 ]; + if (y.invert) y0 = y(y0), y1 = y(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ]; + } + return brush; + }; + brush.clear = function() { + if (!brush.empty()) { + xExtent = [ 0, 0 ], yExtent = [ 0, 0 ]; + xExtentDomain = yExtentDomain = null; + } + return brush; + }; + brush.empty = function() { + return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1]; + }; + return d3.rebind(brush, event, "on"); + }; + var d3_svg_brushCursor = { + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" + }; + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; + var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat; + var d3_time_formatUtc = d3_time_format.utc; + var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ"); + d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; + function d3_time_formatIsoNative(date) { + return date.toISOString(); + } + d3_time_formatIsoNative.parse = function(string) { + var date = new Date(string); + return isNaN(date) ? null : date; + }; + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; + d3_time.second = d3_time_interval(function(date) { + return new d3_date(Math.floor(date / 1e3) * 1e3); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 1e3); + }, function(date) { + return date.getSeconds(); + }); + d3_time.seconds = d3_time.second.range; + d3_time.seconds.utc = d3_time.second.utc.range; + d3_time.minute = d3_time_interval(function(date) { + return new d3_date(Math.floor(date / 6e4) * 6e4); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 6e4); + }, function(date) { + return date.getMinutes(); + }); + d3_time.minutes = d3_time.minute.range; + d3_time.minutes.utc = d3_time.minute.utc.range; + d3_time.hour = d3_time_interval(function(date) { + var timezone = date.getTimezoneOffset() / 60; + return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 36e5); + }, function(date) { + return date.getHours(); + }); + d3_time.hours = d3_time.hour.range; + d3_time.hours.utc = d3_time.hour.utc.range; + d3_time.month = d3_time_interval(function(date) { + date = d3_time.day(date); + date.setDate(1); + return date; + }, function(date, offset) { + date.setMonth(date.getMonth() + offset); + }, function(date) { + return date.getMonth(); + }); + d3_time.months = d3_time.month.range; + d3_time.months.utc = d3_time.month.utc.range; + function d3_time_scale(linear, methods, format) { + function scale(x) { + return linear(x); + } + scale.invert = function(x) { + return d3_time_scaleDate(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); + linear.domain(x); + return scale; + }; + function tickMethod(extent, count) { + var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target); + return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) { + return d / 31536e6; + }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i]; + } + scale.nice = function(interval, skip) { + var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval); + if (method) interval = method[0], skip = method[1]; + function skipped(date) { + return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length; + } + return scale.domain(d3_scale_nice(domain, skip > 1 ? { + floor: function(date) { + while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1); + return date; + }, + ceil: function(date) { + while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1); + return date; + } + } : interval)); + }; + scale.ticks = function(interval, skip) { + var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ { + range: interval + }, skip ]; + if (method) interval = method[0], skip = method[1]; + return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip); + }; + scale.tickFormat = function() { + return format; + }; + scale.copy = function() { + return d3_time_scale(linear.copy(), methods, format); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_time_scaleDate(t) { + return new Date(t); + } + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; + var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ]; + var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) { + return d.getMilliseconds(); + } ], [ ":%S", function(d) { + return d.getSeconds(); + } ], [ "%I:%M", function(d) { + return d.getMinutes(); + } ], [ "%I %p", function(d) { + return d.getHours(); + } ], [ "%a %d", function(d) { + return d.getDay() && d.getDate() != 1; + } ], [ "%b %d", function(d) { + return d.getDate() != 1; + } ], [ "%B", function(d) { + return d.getMonth(); + } ], [ "%Y", d3_true ] ]); + var d3_time_scaleMilliseconds = { + range: function(start, stop, step) { + return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate); + }, + floor: d3_identity, + ceil: d3_identity + }; + d3_time_scaleLocalMethods.year = d3_time.year; + d3_time.scale = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); + }; + var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) { + return [ m[0].utc, m[1] ]; + }); + var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) { + return d.getUTCMilliseconds(); + } ], [ ":%S", function(d) { + return d.getUTCSeconds(); + } ], [ "%I:%M", function(d) { + return d.getUTCMinutes(); + } ], [ "%I %p", function(d) { + return d.getUTCHours(); + } ], [ "%a %d", function(d) { + return d.getUTCDay() && d.getUTCDate() != 1; + } ], [ "%b %d", function(d) { + return d.getUTCDate() != 1; + } ], [ "%B", function(d) { + return d.getUTCMonth(); + } ], [ "%Y", d3_true ] ]); + d3_time_scaleUtcMethods.year = d3_time.year.utc; + d3_time.scale.utc = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat); + }; + d3.text = d3_xhrType(function(request) { + return request.responseText; + }); + d3.json = function(url, callback) { + return d3_xhr(url, "application/json", d3_json, callback); + }; + function d3_json(request) { + return JSON.parse(request.responseText); + } + d3.html = function(url, callback) { + return d3_xhr(url, "text/html", d3_html, callback); + }; + function d3_html(request) { + var range = d3_document.createRange(); + range.selectNode(d3_document.body); + return range.createContextualFragment(request.responseText); + } + d3.xml = d3_xhrType(function(request) { + return request.responseXML; + }); + if (typeof define === "function" && define.amd) define(d3); else if (typeof module === "object" && module.exports) module.exports = d3; + this.d3 = d3; +}(); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/device-stats.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/device-stats.js new file mode 100644 index 000000000..5104ab176 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/device-stats.js @@ -0,0 +1,247 @@ +/* + * 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. + */ + +var xAxis; + +var deviceType = $("#details").data("devicetype"); +var deviceId = $(".device-id").data("deviceid"); +var monitorOperations = $("#details").data("monitor"); +var appContext = $("#details").data("appcontext"); + +var marker1 = appContext + "/public/iot.unit.device.stats/images/map-marker-1.png"; +var marker2 = appContext + "/public/iot.unit.device.stats/images/map-marker-2.png"; + +var map, mapPoints = [], mapPaths = [], mapMarkers = []; +var palette = new Rickshaw.Color.Palette({scheme: "classic9"}); + +function initMap() { + if ($('#map').length) { + map = new google.maps.Map(document.getElementById("map"), { + center: {lat: 6.9344, lng: 79.8428}, + zoom: 12 + }); + } +} + +function formatDates() { + $(".formatDate").each(function () { + var timeStamp = $(this).html(); + $(this).html(getDateString(timeStamp)); + }); +} + +function getDateString(timeStamp) { + var monthNames = [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" + ]; + + var date = new Date(parseInt(timeStamp)); + var day = date.getDate(); + var monthIndex = date.getMonth() + 1; + if (monthIndex < 10) { + monthIndex = "0" + monthIndex; + } + + var year = date.getFullYear(); + var hours = date.getHours(); + var amPm = hours < 12 ? "AM" : "PM"; + + if (hours > 12) { + hours -= 12; + } + if (hours == 0) { + hours = 12; + } + + return day + '-' + monthNames[monthIndex - 1] + '-' + year + ' ' + hours + ':' + date.getMinutes() + amPm; +} + +$(window).on("resize", function () { + location.reload(false); +}); + +$(document).ready(function () { + formatDates(); + updateGraphs(); +}); + +function updateGraphs() { + var tv = 5000; + var graphs = {}; + for (var op in monitorOperations) { + var opName = monitorOperations[op].name; + if (opName == "gps") { + $("#map").removeClass("hidden"); + } else { + var xLabel = "", yLabel = ""; + if (monitorOperations[op].ui_unit) { + var graph_data = monitorOperations[op].ui_unit.data; + for (var d in graph_data) { + if (graph_data[d].hasOwnProperty("column")) { + if (graph_data[d]["column"]["ui-mapping"] == 'x-axis') { + xLabel = graph_data[d]["column"]["label"]; + } else if (graph_data[d]["column"]["ui-mapping"] == 'y-axis') { + yLabel = graph_data[d]["column"]["label"]; + } + } + } + } + var graphHtml = '
      ' + + '
      ' + yLabel + '
      ' + + '
      ' + + '
      ' + + '
      ' + + '
      ' + + '
      ' + + '
      ' + xLabel + '
      ' + + '
      '; + $("#div-chart").append(graphHtml); + + var graph = new Rickshaw.Graph({ + element: document.getElementById("chart-" + opName), + width: $("#chartWrapper").width() - 50, + height: 300, + renderer: "line", + padding: {top: 0.2, left: 0.0, right: 0.0, bottom: 0.2}, + series: new Rickshaw.Series.FixedDuration([{name: monitorOperations[op].name}], undefined, { + timeInterval: 10000, + maxDataPoints: 20, + color: palette.color(), + timeBase: new Date().getTime() / 1000 + }) + }); + + graph.render(); + + xAxis = new Rickshaw.Graph.Axis.Time({ + graph: graph + }); + + xAxis.render(); + + new Rickshaw.Graph.Axis.Y({ + graph: graph, + orientation: 'left', + height: 300, + tickFormat: Rickshaw.Fixtures.Number.formatKMBT, + element: document.getElementById('y_axis-' + opName) + }); + + new Rickshaw.Graph.Legend({ + graph: graph, + element: document.getElementById('legend-' + opName) + }); + + new Rickshaw.Graph.HoverDetail({ + graph: graph, + formatter: function (series, x, y) { + var date = '' + moment(x * 1000).format('Do MMM YYYY h:mm:ss a') + ''; + var swatch = ''; + return swatch + series.name + ": " + parseInt(y) + '
      ' + date; + } + }); + + graphs[opName] = graph; + } + } + + setInterval(function () { + + var getStatsRequest = $.ajax({ + url: appContext + "/api/operations/" + deviceType + "/stats?deviceId=" + + deviceId, + method: "get" + }); + + getStatsRequest.done(function (data) { + var stats = data.data; + var lastUpdate = -1; + for (var s in stats) { + var val = stats[s]; + if (!val) { + continue; + } + if (val.time > lastUpdate) { + lastUpdate = val.time; + } + delete val["time"]; + if (val.map) { + mapPoints.push(val.map); + var marker = new google.maps.Marker({ + position: val.map, + map: map, + icon: marker1, + title: "Seen at " + getDateString(lastUpdate) + }); + marker.setMap(map); + map.panTo(val.map); + mapMarkers.push(marker); + + if (mapPoints.length > 1) { + var l = mapPoints.length; + var path = new google.maps.Polyline({ + path: [mapPoints[l - 1], mapPoints[l - 2]], + geodesic: true, + strokeColor: "#FF0000", + strokeOpacity: 1.0, + strokeWeight: 2 + }); + + path.setMap(map); + mapPaths.push(path); + + mapMarkers[l - 2].setIcon(marker2); + } + + if (mapPoints.length >= 10) { + mapMarkers[0].setMap(null); + mapMarkers.splice(0, 1); + + mapPaths[0].setMap(null); + mapPaths.splice(0, 1); + + mapPoints.splice(0, 1); + } + } else { + var graphVals = {}; + for (var key in val) { + graphVals[key] = val[key]; + graphs[key].series.addData(graphVals); + graphs[key].render(); + } + } + } + + if (lastUpdate == -1) { + $('#last_seen').text("Not seen recently"); + } + + var timeDiff = new Date().getTime() - lastUpdate; + if (timeDiff < tv * 2) { + $('#last_seen').text("Last seen: A while ago"); + } else if (timeDiff < 60 * 1000) { + $('#last_seen').text("Last seen: Less than a minute ago"); + } else if (timeDiff < 60 * 60 * 1000) { + $('#last_seen').text("Last seen: " + Math.round(timeDiff / (60 * 1000)) + + " minutes ago"); + } else { + $('#last_seen').text("Last seen: " + getDateString(lastUpdate)); + } + }); + }, tv); +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/moment.min.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/moment.min.js new file mode 100644 index 000000000..78e5aaadc --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/moment.min.js @@ -0,0 +1,25 @@ +/* + * 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. + */ + +//! moment.js +//! version : 2.10.2 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Ac.apply(null,arguments)}function b(a){Ac=a}function c(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function d(a){return"[object Array]"===Object.prototype.toString.call(a)}function e(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function f(a,b){var c,d=[];for(c=0;c0)for(c in Cc)d=Cc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function m(b){l(this,b),this._d=new Date(+b._d),Dc===!1&&(Dc=!0,a.updateOffset(this),Dc=!1)}function n(a){return a instanceof m||null!=a&&g(a,"_isAMomentObject")}function o(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function p(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&o(a[d])!==o(b[d]))&&g++;return g+f}function q(){}function r(a){return a?a.toLowerCase().replace("_","-"):a}function s(a){for(var b,c,d,e,f=0;f0;){if(d=t(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&p(e,c,!0)>=b-1)break;b--}f++}return null}function t(a){var b=null;if(!Ec[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Bc._abbr,require("./locale/"+a),u(b)}catch(c){}return Ec[a]}function u(a,b){var c;return a&&(c="undefined"==typeof b?w(a):v(a,b),c&&(Bc=c)),Bc._abbr}function v(a,b){return null!==b?(b.abbr=a,Ec[a]||(Ec[a]=new q),Ec[a].set(b),u(a),Ec[a]):(delete Ec[a],null)}function w(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Bc;if(!d(a)){if(b=t(a))return b;a=[a]}return s(a)}function x(a,b){var c=a.toLowerCase();Fc[c]=Fc[c+"s"]=Fc[b]=a}function y(a){return"string"==typeof a?Fc[a]||Fc[a.toLowerCase()]:void 0}function z(a){var b,c,d={};for(c in a)g(a,c)&&(b=y(c),b&&(d[b]=a[c]));return d}function A(b,c){return function(d){return null!=d?(C(this,b,d),a.updateOffset(this,c),this):B(this,b)}}function B(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function C(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function D(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=y(a),"function"==typeof this[a])return this[a](b);return this}function E(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthb;b++)d[b]=Jc[d[b]]?Jc[d[b]]:G(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function I(a,b){return a.isValid()?(b=J(b,a.localeData()),Ic[b]||(Ic[b]=H(b)),Ic[b](a)):a.localeData().invalidDate()}function J(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Hc.lastIndex=0;d>=0&&Hc.test(a);)a=a.replace(Hc,c),Hc.lastIndex=0,d-=1;return a}function K(a,b,c){Yc[a]="function"==typeof b?b:function(a){return a&&c?c:b}}function L(a,b){return g(Yc,a)?Yc[a](b._strict,b._locale):new RegExp(M(a))}function M(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function N(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=o(a)}),c=0;cd;d++){if(e=i([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function U(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),Q(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function V(b){return null!=b?(U(this,b),a.updateOffset(this,!0),this):B(this,"Month")}function W(){return Q(this.year(),this.month())}function X(a){var b,c=a._a;return c&&-2===a._pf.overflow&&(b=c[_c]<0||c[_c]>11?_c:c[ad]<1||c[ad]>Q(c[$c],c[_c])?ad:c[bd]<0||c[bd]>24||24===c[bd]&&(0!==c[cd]||0!==c[dd]||0!==c[ed])?bd:c[cd]<0||c[cd]>59?cd:c[dd]<0||c[dd]>59?dd:c[ed]<0||c[ed]>999?ed:-1,a._pf._overflowDayOfYear&&($c>b||b>ad)&&(b=ad),a._pf.overflow=b),a}function Y(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function Z(a,b){var c=!0;return h(function(){return c&&(Y(a),c=!1),b.apply(this,arguments)},b)}function $(a,b){hd[a]||(Y(b),hd[a]=!0)}function _(a){var b,c,d=a._i,e=id.exec(d);if(e){for(a._pf.iso=!0,b=0,c=jd.length;c>b;b++)if(jd[b][1].exec(d)){a._f=jd[b][0]+(e[6]||" ");break}for(b=0,c=kd.length;c>b;b++)if(kd[b][1].exec(d)){a._f+=kd[b][0];break}d.match(Vc)&&(a._f+="Z"),sa(a)}else a._isValid=!1}function aa(b){var c=ld.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(_(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ba(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function ca(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function da(a){return ea(a)?366:365}function ea(a){return a%4===0&&a%100!==0||a%400===0}function fa(){return ea(this.year())}function ga(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=za(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ha(a){return ga(a,this._week.dow,this._week.doy).week}function ia(){return this._week.dow}function ja(){return this._week.doy}function ka(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function la(a){var b=ga(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function ma(a,b,c,d,e){var f,g,h=ca(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:da(a-1)+g}}function na(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function oa(a,b,c){return null!=a?a:null!=b?b:c}function pa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function qa(a){var b,c,d,e,f=[];if(!a._d){for(d=pa(a),a._w&&null==a._a[ad]&&null==a._a[_c]&&ra(a),a._dayOfYear&&(e=oa(a._a[$c],d[$c]),a._dayOfYear>da(e)&&(a._pf._overflowDayOfYear=!0),c=ca(e,0,a._dayOfYear),a._a[_c]=c.getUTCMonth(),a._a[ad]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[bd]&&0===a._a[cd]&&0===a._a[dd]&&0===a._a[ed]&&(a._nextDay=!0,a._a[bd]=0),a._d=(a._useUTC?ca:ba).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[bd]=24)}}function ra(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=oa(b.GG,a._a[$c],ga(za(),1,4).year),d=oa(b.W,1),e=oa(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=oa(b.gg,a._a[$c],ga(za(),f,g).year),d=oa(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=ma(c,d,e,g,f),a._a[$c]=h.year,a._dayOfYear=h.dayOfYear}function sa(b){if(b._f===a.ISO_8601)return void _(b);b._a=[],b._pf.empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=J(b._f,b._locale).match(Gc)||[],c=0;c0&&b._pf.unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),Jc[f]?(d?b._pf.empty=!1:b._pf.unusedTokens.push(f),P(f,d,b)):b._strict&&!d&&b._pf.unusedTokens.push(f);b._pf.charsLeftOver=i-j,h.length>0&&b._pf.unusedInput.push(h),b._pf.bigHour===!0&&b._a[bd]<=12&&(b._pf.bigHour=void 0),b._a[bd]=ta(b._locale,b._a[bd],b._meridiem),qa(b),X(b)}function ta(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function ua(a){var b,d,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,d=b));h(a,d||b)}function va(a){if(!a._d){var b=z(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],qa(a)}}function wa(a){var b,c=a._i,e=a._f;return a._locale=a._locale||w(a._l),null===c||void 0===e&&""===c?k({nullInput:!0}):("string"==typeof c&&(a._i=c=a._locale.preparse(c)),n(c)?new m(X(c)):(d(e)?ua(a):e?sa(a):xa(a),b=new m(X(a)),b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b))}function xa(b){var c=b._i;void 0===c?b._d=new Date:e(c)?b._d=new Date(+c):"string"==typeof c?aa(b):d(c)?(b._a=f(c.slice(0),function(a){return parseInt(a,10)}),qa(b)):"object"==typeof c?va(b):"number"==typeof c?b._d=new Date(c):a.createFromInputFallback(b)}function ya(a,b,d,e,f){var g={};return"boolean"==typeof d&&(e=d,d=void 0),g._isAMomentObject=!0,g._useUTC=g._isUTC=f,g._l=d,g._i=a,g._f=b,g._strict=e,g._pf=c(),wa(g)}function za(a,b,c,d){return ya(a,b,c,d,!1)}function Aa(a,b){var c,e;if(1===b.length&&d(b[0])&&(b=b[0]),!b.length)return za();for(c=b[0],e=1;ea&&(a=-a,c="-"),c+E(~~(a/60),2)+b+E(~~a%60,2)})}function Ga(a){var b=(a||"").match(Vc)||[],c=b[b.length-1]||[],d=(c+"").match(qd)||["-",0,0],e=+(60*d[1])+o(d[2]);return"+"===d[0]?e:-e}function Ha(b,c){var d,f;return c._isUTC?(d=c.clone(),f=(n(b)||e(b)?+b:+za(b))-+d,d._d.setTime(+d._d+f),a.updateOffset(d,!1),d):za(b).local();return c._isUTC?za(b).zone(c._offset||0):za(b).local()}function Ia(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Ja(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ga(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ia(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Za(this,Ua(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ia(this)}function Ka(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function La(a){return this.utcOffset(0,a)}function Ma(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ia(this),"m")),this}function Na(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ga(this._i)),this}function Oa(a){return a=a?za(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Pa(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Qa(){if(this._a){var a=this._isUTC?i(this._a):za(this._a);return this.isValid()&&p(this._a,a.toArray())>0}return!1}function Ra(){return!this._isUTC}function Sa(){return this._isUTC}function Ta(){return this._isUTC&&0===this._offset}function Ua(a,b){var c,d,e,f=a,h=null;return Ea(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(h=rd.exec(a))?(c="-"===h[1]?-1:1,f={y:0,d:o(h[ad])*c,h:o(h[bd])*c,m:o(h[cd])*c,s:o(h[dd])*c,ms:o(h[ed])*c}):(h=sd.exec(a))?(c="-"===h[1]?-1:1,f={y:Va(h[2],c),M:Va(h[3],c),d:Va(h[4],c),h:Va(h[5],c),m:Va(h[6],c),s:Va(h[7],c),w:Va(h[8],c)}):null==f?f={}:"object"==typeof f&&("from"in f||"to"in f)&&(e=Xa(za(f.from),za(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new Da(f),Ea(a)&&g(a,"_locale")&&(d._locale=a._locale),d}function Va(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Wa(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Xa(a,b){var c;return b=Ha(b,a),a.isBefore(b)?c=Wa(a,b):(c=Wa(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function Ya(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||($(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ua(c,d),Za(this,e,a),this}}function Za(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&C(b,"Date",B(b,"Date")+g*d),h&&U(b,B(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function $a(a){var b=a||za(),c=Ha(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,za(b)))}function _a(){return new m(this)}function ab(a,b){var c;return b=y("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=n(a)?a:za(a),+this>+a):(c=n(a)?+a:+za(a),c<+this.clone().startOf(b))}function bb(a,b){var c;return b=y("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=n(a)?a:za(a),+a>+this):(c=n(a)?+a:+za(a),+this.clone().endOf(b)a?Math.ceil(a):Math.floor(a)}function fb(a,b,c){var d,e,f=Ha(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=y(b),"year"===b||"month"===b||"quarter"===b?(e=gb(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:eb(e)}function gb(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function hb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function ib(){var a=this.clone().utc();return 0b;b++)if(this._weekdaysParse[b]||(c=za([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b}function Jb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Eb(a,this.localeData()),this.add(a-b,"d")):b}function Kb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Lb(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Mb(a,b){F(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Nb(a,b){return b._meridiemParse}function Ob(a){return"p"===(a+"").toLowerCase().charAt(0)}function Pb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Qb(a){F(0,[a,3],0,"millisecond")}function Rb(){return this._isUTC?"UTC":""}function Sb(){return this._isUTC?"Coordinated Universal Time":""}function Tb(a){return za(1e3*a)}function Ub(){return za.apply(null,arguments).parseZone()}function Vb(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function Wb(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b}function Xb(){return this._invalidDate}function Yb(a){return this._ordinal.replace("%d",a)}function Zb(a){return a}function $b(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function _b(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function ac(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function bc(a,b,c,d){var e=w(),f=i().set(d,b);return e[c](f,a)}function cc(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return bc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=bc(a,f,c,e);return g}function dc(a,b){return cc(a,b,"months",12,"month")}function ec(a,b){return cc(a,b,"monthsShort",12,"month")}function fc(a,b){return cc(a,b,"weekdays",7,"day")}function gc(a,b){return cc(a,b,"weekdaysShort",7,"day")}function hc(a,b){return cc(a,b,"weekdaysMin",7,"day")}function ic(){var a=this._data;return this._milliseconds=Od(this._milliseconds),this._days=Od(this._days),this._months=Od(this._months),a.milliseconds=Od(a.milliseconds),a.seconds=Od(a.seconds),a.minutes=Od(a.minutes),a.hours=Od(a.hours),a.months=Od(a.months),a.years=Od(a.years),this}function jc(a,b,c,d){var e=Ua(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function kc(a,b){return jc(this,a,b,1)}function lc(a,b){return jc(this,a,b,-1)}function mc(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;return g.milliseconds=d%1e3,a=eb(d/1e3),g.seconds=a%60,b=eb(a/60),g.minutes=b%60,c=eb(b/60),g.hours=c%24,e+=eb(c/24),h=eb(nc(e)),e-=eb(oc(h)),f+=eb(e/30),e%=30,h+=eb(f/12),f%=12,g.days=e,g.months=f,g.years=h,this}function nc(a){return 400*a/146097}function oc(a){return 146097*a/400}function pc(a){var b,c,d=this._milliseconds;if(a=y(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+12*nc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(oc(this._months/12)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 24*b*60+d/6e4;case"second":return 24*b*60*60+d/1e3;case"millisecond":return Math.floor(24*b*60*60*1e3)+d;default:throw new Error("Unknown unit "+a)}}function qc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*o(this._months/12)}function rc(a){return function(){return this.as(a)}}function sc(a){return a=y(a),this[a+"s"]()}function tc(a){return function(){return this._data[a]}}function uc(){return eb(this.days()/7)}function vc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function wc(a,b,c){var d=Ua(a).abs(),e=ce(d.as("s")),f=ce(d.as("m")),g=ce(d.as("h")),h=ce(d.as("d")),i=ce(d.as("M")),j=ce(d.as("y")),k=e0,k[4]=c,vc.apply(null,k)}function xc(a,b){return void 0===de[a]?!1:void 0===b?de[a]:(de[a]=b,!0)}function yc(a){var b=this.localeData(),c=wc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function zc(){var a=ee(this.years()),b=ee(this.months()),c=ee(this.days()),d=ee(this.hours()),e=ee(this.minutes()),f=ee(this.seconds()+this.milliseconds()/1e3),g=this.asSeconds();return g?(0>g?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"}var Ac,Bc,Cc=a.momentProperties=[],Dc=!1,Ec={},Fc={},Gc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,Hc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ic={},Jc={},Kc=/\d/,Lc=/\d\d/,Mc=/\d{3}/,Nc=/\d{4}/,Oc=/[+-]?\d{6}/,Pc=/\d\d?/,Qc=/\d{1,3}/,Rc=/\d{1,4}/,Sc=/[+-]?\d{1,6}/,Tc=/\d+/,Uc=/[+-]?\d+/,Vc=/Z|[+-]\d\d:?\d\d/gi,Wc=/[+-]?\d+(\.\d{1,3})?/,Xc=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Yc={},Zc={},$c=0,_c=1,ad=2,bd=3,cd=4,dd=5,ed=6;F("M",["MM",2],"Mo",function(){return this.month()+1}),F("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),F("MMMM",0,0,function(a){return this.localeData().months(this,a)}),x("month","M"),K("M",Pc),K("MM",Pc,Lc),K("MMM",Xc),K("MMMM",Xc),N(["M","MM"],function(a,b){b[_c]=o(a)-1}),N(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[_c]=e:c._pf.invalidMonth=a});var fd="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),gd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),hd={};a.suppressDeprecationWarnings=!1;var id=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,jd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],kd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],ld=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=Z("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),F(0,["YY",2],0,function(){return this.year()%100}),F(0,["YYYY",4],0,"year"),F(0,["YYYYY",5],0,"year"),F(0,["YYYYYY",6,!0],0,"year"),x("year","y"),K("Y",Uc),K("YY",Pc,Lc),K("YYYY",Rc,Nc),K("YYYYY",Sc,Oc),K("YYYYYY",Sc,Oc),N(["YYYY","YYYYY","YYYYYY"],$c),N("YY",function(b,c){c[$c]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return o(a)+(o(a)>68?1900:2e3)};var md=A("FullYear",!1);F("w",["ww",2],"wo","week"),F("W",["WW",2],"Wo","isoWeek"),x("week","w"),x("isoWeek","W"),K("w",Pc),K("ww",Pc,Lc),K("W",Pc),K("WW",Pc,Lc),O(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=o(a)});var nd={dow:0,doy:6};F("DDD",["DDDD",3],"DDDo","dayOfYear"),x("dayOfYear","DDD"),K("DDD",Qc),K("DDDD",Mc),N(["DDD","DDDD"],function(a,b,c){c._dayOfYear=o(a)}),a.ISO_8601=function(){};var od=Z("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=za.apply(null,arguments);return this>a?this:a}),pd=Z("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=za.apply(null,arguments);return a>this?this:a});Fa("Z",":"),Fa("ZZ",""),K("Z",Vc),K("ZZ",Vc),N(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ga(a)});var qd=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var rd=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,sd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Ua.fn=Da.prototype;var td=Ya(1,"add"),ud=Ya(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var vd=Z("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});F(0,["gg",2],0,function(){return this.weekYear()%100}),F(0,["GG",2],0,function(){return this.isoWeekYear()%100}),xb("gggg","weekYear"),xb("ggggg","weekYear"),xb("GGGG","isoWeekYear"),xb("GGGGG","isoWeekYear"),x("weekYear","gg"),x("isoWeekYear","GG"),K("G",Uc),K("g",Uc),K("GG",Pc,Lc),K("gg",Pc,Lc),K("GGGG",Rc,Nc),K("gggg",Rc,Nc),K("GGGGG",Sc,Oc),K("ggggg",Sc,Oc),O(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=o(a)}),O(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),F("Q",0,0,"quarter"),x("quarter","Q"),K("Q",Kc),N("Q",function(a,b){b[_c]=3*(o(a)-1)}),F("D",["DD",2],"Do","date"),x("date","D"),K("D",Pc),K("DD",Pc,Lc),K("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),N(["D","DD"],ad),N("Do",function(a,b){b[ad]=o(a.match(Pc)[0],10)});var wd=A("Date",!0);F("d",0,"do","day"),F("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),F("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),F("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),F("e",0,0,"weekday"),F("E",0,0,"isoWeekday"),x("day","d"),x("weekday","e"),x("isoWeekday","E"),K("d",Pc),K("e",Pc),K("E",Pc),K("dd",Xc),K("ddd",Xc),K("dddd",Xc),O(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:c._pf.invalidWeekday=a}),O(["d","e","E"],function(a,b,c,d){b[d]=o(a)});var xd="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),yd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),zd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");F("H",["HH",2],0,"hour"),F("h",["hh",2],0,function(){return this.hours()%12||12}),Mb("a",!0),Mb("A",!1),x("hour","h"),K("a",Nb),K("A",Nb),K("H",Pc),K("h",Pc),K("HH",Pc,Lc),K("hh",Pc,Lc),N(["H","HH"],bd),N(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),N(["h","hh"],function(a,b,c){b[bd]=o(a),c._pf.bigHour=!0});var Ad=/[ap]\.?m?\.?/i,Bd=A("Hours",!0);F("m",["mm",2],0,"minute"),x("minute","m"),K("m",Pc),K("mm",Pc,Lc),N(["m","mm"],cd);var Cd=A("Minutes",!1);F("s",["ss",2],0,"second"),x("second","s"),K("s",Pc),K("ss",Pc,Lc),N(["s","ss"],dd);var Dd=A("Seconds",!1);F("S",0,0,function(){return~~(this.millisecond()/100)}),F(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Qb("SSS"),Qb("SSSS"),x("millisecond","ms"),K("S",Qc,Kc),K("SS",Qc,Lc),K("SSS",Qc,Mc),K("SSSS",Tc),N(["S","SS","SSS","SSSS"],function(a,b){b[ed]=o(1e3*("0."+a))});var Ed=A("Milliseconds",!1);F("z",0,0,"zoneAbbr"),F("zz",0,0,"zoneName");var Fd=m.prototype;Fd.add=td,Fd.calendar=$a,Fd.clone=_a,Fd.diff=fb,Fd.endOf=pb,Fd.format=jb,Fd.from=kb,Fd.fromNow=lb,Fd.get=D,Fd.invalidAt=wb,Fd.isAfter=ab,Fd.isBefore=bb,Fd.isBetween=cb,Fd.isSame=db,Fd.isValid=ub,Fd.lang=vd,Fd.locale=mb,Fd.localeData=nb,Fd.max=pd,Fd.min=od,Fd.parsingFlags=vb,Fd.set=D,Fd.startOf=ob,Fd.subtract=ud,Fd.toArray=tb,Fd.toDate=sb,Fd.toISOString=ib,Fd.toJSON=ib,Fd.toString=hb,Fd.unix=rb,Fd.valueOf=qb,Fd.year=md,Fd.isLeapYear=fa,Fd.weekYear=zb,Fd.isoWeekYear=Ab,Fd.quarter=Fd.quarters=Db,Fd.month=V,Fd.daysInMonth=W,Fd.week=Fd.weeks=ka,Fd.isoWeek=Fd.isoWeeks=la,Fd.weeksInYear=Cb,Fd.isoWeeksInYear=Bb,Fd.date=wd,Fd.day=Fd.days=Jb,Fd.weekday=Kb,Fd.isoWeekday=Lb,Fd.dayOfYear=na,Fd.hour=Fd.hours=Bd,Fd.minute=Fd.minutes=Cd,Fd.second=Fd.seconds=Dd,Fd.millisecond=Fd.milliseconds=Ed,Fd.utcOffset=Ja,Fd.utc=La,Fd.local=Ma,Fd.parseZone=Na,Fd.hasAlignedHourOffset=Oa,Fd.isDST=Pa,Fd.isDSTShifted=Qa,Fd.isLocal=Ra,Fd.isUtcOffset=Sa,Fd.isUtc=Ta,Fd.isUTC=Ta,Fd.zoneAbbr=Rb,Fd.zoneName=Sb,Fd.dates=Z("dates accessor is deprecated. Use date instead.",wd),Fd.months=Z("months accessor is deprecated. Use month instead",V),Fd.years=Z("years accessor is deprecated. Use year instead",md),Fd.zone=Z("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Ka);var Gd=Fd,Hd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Id={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},Jd="Invalid date",Kd="%d",Ld=/\d{1,2}/,Md={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Nd=q.prototype;Nd._calendar=Hd,Nd.calendar=Vb,Nd._longDateFormat=Id,Nd.longDateFormat=Wb,Nd._invalidDate=Jd,Nd.invalidDate=Xb,Nd._ordinal=Kd,Nd.ordinal=Yb,Nd._ordinalParse=Ld, +Nd.preparse=Zb,Nd.postformat=Zb,Nd._relativeTime=Md,Nd.relativeTime=$b,Nd.pastFuture=_b,Nd.set=ac,Nd.months=R,Nd._months=fd,Nd.monthsShort=S,Nd._monthsShort=gd,Nd.monthsParse=T,Nd.week=ha,Nd._week=nd,Nd.firstDayOfYear=ja,Nd.firstDayOfWeek=ia,Nd.weekdays=Fb,Nd._weekdays=xd,Nd.weekdaysMin=Hb,Nd._weekdaysMin=zd,Nd.weekdaysShort=Gb,Nd._weekdaysShort=yd,Nd.weekdaysParse=Ib,Nd.isPM=Ob,Nd._meridiemParse=Ad,Nd.meridiem=Pb,u("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===o(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=Z("moment.lang is deprecated. Use moment.locale instead.",u),a.langData=Z("moment.langData is deprecated. Use moment.localeData instead.",w);var Od=Math.abs,Pd=rc("ms"),Qd=rc("s"),Rd=rc("m"),Sd=rc("h"),Td=rc("d"),Ud=rc("w"),Vd=rc("M"),Wd=rc("y"),Xd=tc("milliseconds"),Yd=tc("seconds"),Zd=tc("minutes"),$d=tc("hours"),_d=tc("days"),ae=tc("months"),be=tc("years"),ce=Math.round,de={s:45,m:45,h:22,d:26,M:11},ee=Math.abs,fe=Da.prototype;fe.abs=ic,fe.add=kc,fe.subtract=lc,fe.as=pc,fe.asMilliseconds=Pd,fe.asSeconds=Qd,fe.asMinutes=Rd,fe.asHours=Sd,fe.asDays=Td,fe.asWeeks=Ud,fe.asMonths=Vd,fe.asYears=Wd,fe.valueOf=qc,fe._bubble=mc,fe.get=sc,fe.milliseconds=Xd,fe.seconds=Yd,fe.minutes=Zd,fe.hours=$d,fe.days=_d,fe.weeks=uc,fe.months=ae,fe.years=be,fe.humanize=yc,fe.toISOString=zc,fe.toString=zc,fe.toJSON=zc,fe.locale=mb,fe.localeData=nb,fe.toIsoString=Z("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",zc),fe.lang=vd,F("X",0,0,"unix"),F("x",0,0,"valueOf"),K("x",Uc),K("X",Wc),N("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),N("x",function(a,b,c){c._d=new Date(o(a))}),a.version="2.10.2",b(za),a.fn=Gd,a.min=Ba,a.max=Ca,a.utc=i,a.unix=Tb,a.months=dc,a.isDate=e,a.locale=u,a.invalid=k,a.duration=Ua,a.isMoment=n,a.weekdays=fc,a.parseZone=Ub,a.localeData=w,a.isDuration=Ea,a.monthsShort=ec,a.weekdaysMin=hc,a.defineLocale=v,a.weekdaysShort=gc,a.normalizeUnits=y,a.relativeTimeThreshold=xc;var ge=a;return ge}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/rickshaw.min.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/rickshaw.min.js new file mode 100644 index 000000000..be060e0b8 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/public/js/rickshaw.min.js @@ -0,0 +1,21 @@ +/* + * 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(root,factory){if(typeof define==="function"&&define.amd){define(["d3.min"],function(d3){return root.Rickshaw=factory(d3)})}else if(typeof exports==="object"){module.exports=factory(require("d3"))}else{root.Rickshaw=factory(d3)}})(this,function(d3){var Rickshaw={namespace:function(namespace,obj){var parts=namespace.split(".");var parent=Rickshaw;for(var i=1,length=parts.length;i0){var x=s.data[0].x;var y=s.data[0].y;if(typeof x!="number"||typeof y!="number"&&y!==null){throw"x and y properties of points should be numbers instead of "+typeof x+" and "+typeof y}}if(s.data.length>=3){if(s.data[2].xthis.window.xMax)isInRange=false;return isInRange}return true};this.onUpdate=function(callback){this.updateCallbacks.push(callback)};this.onConfigure=function(callback){this.configureCallbacks.push(callback)};this.registerRenderer=function(renderer){this._renderers=this._renderers||{};this._renderers[renderer.name]=renderer};this.configure=function(args){this.config=this.config||{};if(args.width||args.height){this.setSize(args)}Rickshaw.keys(this.defaults).forEach(function(k){this.config[k]=k in args?args[k]:k in this?this[k]:this.defaults[k]},this);Rickshaw.keys(this.config).forEach(function(k){this[k]=this.config[k]},this);if("stack"in args)args.unstack=!args.stack;var renderer=args.renderer||this.renderer&&this.renderer.name||"stack";this.setRenderer(renderer,args);this.configureCallbacks.forEach(function(callback){callback(args)})};this.setRenderer=function(r,args){if(typeof r=="function"){this.renderer=new r({graph:self});this.registerRenderer(this.renderer)}else{if(!this._renderers[r]){throw"couldn't find renderer "+r}this.renderer=this._renderers[r]}if(typeof args=="object"){this.renderer.configure(args)}};this.setSize=function(args){args=args||{};if(typeof window!==undefined){var style=window.getComputedStyle(this.element,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);var elementHeight=parseInt(style.getPropertyValue("height"),10)}this.width=args.width||elementWidth||400;this.height=args.height||elementHeight||250;this.vis&&this.vis.attr("width",this.width).attr("height",this.height)};this.initialize(args)};Rickshaw.namespace("Rickshaw.Fixtures.Color");Rickshaw.Fixtures.Color=function(){this.schemes={};this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse();this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"];this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"];this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse();this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"};this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse();this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"];this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]};Rickshaw.namespace("Rickshaw.Fixtures.RandomData");Rickshaw.Fixtures.RandomData=function(timeInterval){var addData;timeInterval=timeInterval||1;var lastRandomValue=200;var timeBase=Math.floor((new Date).getTime()/1e3);this.addData=function(data){var randomValue=Math.random()*100+15+lastRandomValue;var index=data[0].length;var counter=1;data.forEach(function(series){var randomVariance=Math.random()*20;var v=randomValue/25+counter++ +(Math.cos(index*counter*11/960)+2)*15+(Math.cos(index/7)+2)*7+(Math.cos(index/17)+2)*1;series.push({x:index*timeInterval+timeBase,y:v+randomVariance})});lastRandomValue=randomValue*.85};this.removeData=function(data){data.forEach(function(series){series.shift()});timeBase+=timeInterval}};Rickshaw.namespace("Rickshaw.Fixtures.Time");Rickshaw.Fixtures.Time=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getUTCFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getUTCFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getUTCMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getUTCDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getUTCMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getUTCMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toUTCString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="month"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),date.getUTCMonth())/1e3;if(floor==time)return time;year=date.getUTCFullYear();var month=date.getUTCMonth();if(month==11){month=0;year=year+1}else{month+=1}return Date.UTC(year,month)/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),0)/1e3;if(floor==time)return time;year=date.getUTCFullYear()+1;return Date.UTC(year,0)/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Time.Local");Rickshaw.Fixtures.Time.Local=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="day"){var nearFuture=new Date((time+unit.seconds-1)*1e3);var rounded=new Date(0);rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(nearFuture.getDate());rounded.setMonth(nearFuture.getMonth());rounded.setFullYear(nearFuture.getFullYear());return rounded.getTime()/1e3}if(unit.name=="month"){date=new Date(time*1e3);floor=new Date(date.getFullYear(),date.getMonth()).getTime()/1e3;if(floor==time)return time;year=date.getFullYear();var month=date.getMonth();if(month==11){month=0;year=year+1}else{month+=1}return new Date(year,month).getTime()/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=new Date(date.getUTCFullYear(),0).getTime()/1e3;if(floor==time)return time;year=date.getFullYear()+1;return new Date(year,0).getTime()/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Number");Rickshaw.Fixtures.Number.formatKMBT=function(y){var abs_y=Math.abs(y);if(abs_y>=1e12){return y/1e12+"T"}else if(abs_y>=1e9){return y/1e9+"B"}else if(abs_y>=1e6){return y/1e6+"M"}else if(abs_y>=1e3){return y/1e3+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(y){var abs_y=Math.abs(y);if(abs_y>=0x4000000000000){return y/0x4000000000000+"P"}else if(abs_y>=1099511627776){return y/1099511627776+"T"}else if(abs_y>=1073741824){return y/1073741824+"G"}else if(abs_y>=1048576){return y/1048576+"M"}else if(abs_y>=1024){return y/1024+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.namespace("Rickshaw.Color.Palette");Rickshaw.Color.Palette=function(args){var color=new Rickshaw.Fixtures.Color;args=args||{};this.schemes={};this.scheme=color.schemes[args.scheme]||args.scheme||color.schemes.colorwheel;this.runningIndex=0;this.generatorIndex=0;if(args.interpolatedStopCount){var schemeCount=this.scheme.length-1;var i,j,scheme=[];for(i=0;iself.graph.x.range()[1]){if(annotation.element){annotation.line.classList.add("offscreen");annotation.element.style.display="none"}annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.add("offscreen")});return}if(!annotation.element){var element=annotation.element=document.createElement("div");element.classList.add("annotation");this.elements.timeline.appendChild(element);element.addEventListener("click",function(e){element.classList.toggle("active");annotation.line.classList.toggle("active");annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.toggle("active")})},false)}annotation.element.style.left=left+"px";annotation.element.style.display="block";annotation.boxes.forEach(function(box){var element=box.element;if(!element){element=box.element=document.createElement("div");element.classList.add("content");element.innerHTML=box.content;annotation.element.appendChild(element);annotation.line=document.createElement("div");annotation.line.classList.add("annotation_line");self.graph.element.appendChild(annotation.line);if(box.end){box.rangeElement=document.createElement("div");box.rangeElement.classList.add("annotation_range");self.graph.element.appendChild(box.rangeElement)}}if(box.end){var annotationRangeStart=left;var annotationRangeEnd=Math.min(self.graph.x(box.end),self.graph.x.range()[1]);if(annotationRangeStart>annotationRangeEnd){annotationRangeEnd=left;annotationRangeStart=Math.max(self.graph.x(box.end),self.graph.x.range()[0])}var annotationRangeWidth=annotationRangeEnd-annotationRangeStart;box.rangeElement.style.left=annotationRangeStart+"px";box.rangeElement.style.width=annotationRangeWidth+"px";box.rangeElement.classList.remove("offscreen")}annotation.line.classList.remove("offscreen");annotation.line.style.left=left+"px"})},this)};this.graph.onUpdate(function(){self.update()})};Rickshaw.namespace("Rickshaw.Graph.Axis.Time");Rickshaw.Graph.Axis.Time=function(args){var self=this;this.graph=args.graph;this.elements=[];this.ticksTreatment=args.ticksTreatment||"plain";this.fixedTimeUnit=args.timeUnit;var time=args.timeFixture||new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var unit;var units=time.units;var domain=this.graph.x.domain();var rangeSeconds=domain[1]-domain[0];units.forEach(function(u){if(Math.floor(rangeSeconds/u.seconds)>=2){unit=unit||u}});return unit||time.units[time.units.length-1]};this.tickOffsets=function(){var domain=this.graph.x.domain();var unit=this.fixedTimeUnit||this.appropriateTimeUnit();var count=Math.ceil((domain[1]-domain[0])/unit.seconds);var runningTick=domain[0];var offsets=[];for(var i=0;iself.graph.x.range()[1])return;var element=document.createElement("div");element.style.left=self.graph.x(o.value)+"px";element.classList.add("x_tick");element.classList.add(self.ticksTreatment);var title=document.createElement("div");title.classList.add("title");title.innerHTML=o.unit.formatter(new Date(o.value*1e3));element.appendChild(title);self.graph.element.appendChild(element);self.elements.push(element)})};this.graph.onUpdate(function(){self.render()})};Rickshaw.namespace("Rickshaw.Graph.Axis.X");Rickshaw.Graph.Axis.X=function(args){var self=this;var berthRate=.1;this.initialize=function(args){this.graph=args.graph;this.orientation=args.orientation||"top";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";if(args.element){this.element=args.element;this._discoverSize(args.element,args);this.vis=d3.select(args.element).append("svg:svg").attr("height",this.height).attr("width",this.width).attr("class","rickshaw_graph x_axis_d3");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}this.graph.onUpdate(function(){self.render()})};this.setSize=function(args){args=args||{};if(!this.element)return;this._discoverSize(this.element.parentNode,args);this.vis.attr("height",this.height).attr("width",this.width*(1+berthRate));var berth=Math.floor(this.width*berthRate/2);this.element.style.left=-1*berth+"px"};this.render=function(){if(this._renderWidth!==undefined&&this.graph.width!==this._renderWidth)this.setSize({auto:true});var axis=d3.svg.axis().scale(this.graph.x).orient(this.orientation);axis.tickFormat(args.tickFormat||function(x){return x});if(this.tickValues)axis.tickValues(this.tickValues);this.ticks=this.staticTicks||Math.floor(this.graph.width/this.pixelsPerTick);var berth=Math.floor(this.width*berthRate/2)||0;var transform;if(this.orientation=="top"){var yOffset=this.height||this.graph.height;transform="translate("+berth+","+yOffset+")"}else{transform="translate("+berth+", 0)"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["x_ticks_d3",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var gridSize=(this.orientation=="bottom"?1:-1)*this.graph.height;this.graph.vis.append("svg:g").attr("class","x_grid_d3").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-x-value",this.textContent)});this._renderHeight=this.graph.height};this._discoverSize=function(element,args){if(typeof window!=="undefined"){var style=window.getComputedStyle(element,null);var elementHeight=parseInt(style.getPropertyValue("height"),10);if(!args.auto){var elementWidth=parseInt(style.getPropertyValue("width"),10)}}this.width=(args.width||elementWidth||this.graph.width)*(1+berthRate);this.height=args.height||elementHeight||40};this.initialize(args)};Rickshaw.namespace("Rickshaw.Graph.Axis.Y");Rickshaw.Graph.Axis.Y=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.orientation=args.orientation||"right";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";this.tickFormat=args.tickFormat||function(y){return y};this.berthRate=.1;if(args.element){this.element=args.element;this.vis=d3.select(args.element).append("svg:svg").attr("class","rickshaw_graph y_axis");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}var self=this;this.graph.onUpdate(function(){self.render()})},setSize:function(args){args=args||{};if(!this.element)return;if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element.parentNode,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);if(!args.auto){var elementHeight=parseInt(style.getPropertyValue("height"),10)}}this.width=args.width||elementWidth||this.graph.width*this.berthRate;this.height=args.height||elementHeight||this.graph.height;this.vis.attr("width",this.width).attr("height",this.height*(1+this.berthRate));var berth=this.height*this.berthRate;if(this.orientation=="left"){this.element.style.top=-1*berth+"px"}},render:function(){if(this._renderHeight!==undefined&&this.graph.height!==this._renderHeight)this.setSize({auto:true});this.ticks=this.staticTicks||Math.floor(this.graph.height/this.pixelsPerTick);var axis=this._drawAxis(this.graph.y);this._drawGrid(axis);this._renderHeight=this.graph.height},_drawAxis:function(scale){var axis=d3.svg.axis().scale(scale).orient(this.orientation);axis.tickFormat(this.tickFormat);if(this.tickValues)axis.tickValues(this.tickValues);if(this.orientation=="left"){var berth=this.height*this.berthRate;var transform="translate("+this.width+", "+berth+")"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));return axis},_drawGrid:function(axis){var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-y-value",this.textContent) +})}});Rickshaw.namespace("Rickshaw.Graph.Axis.Y.Scaled");Rickshaw.Graph.Axis.Y.Scaled=Rickshaw.Class.create(Rickshaw.Graph.Axis.Y,{initialize:function($super,args){if(typeof args.scale==="undefined"){throw new Error("Scaled requires scale")}this.scale=args.scale;if(typeof args.grid==="undefined"){this.grid=true}else{this.grid=args.grid}$super(args)},_drawAxis:function($super,scale){var domain=this.scale.domain();var renderDomain=this.graph.renderer.domain().y;var extents=[Math.min.apply(Math,domain),Math.max.apply(Math,domain)];var extentMap=d3.scale.linear().domain([0,1]).range(extents);var adjExtents=[extentMap(renderDomain[0]),extentMap(renderDomain[1])];var adjustment=d3.scale.linear().domain(extents).range(adjExtents);var adjustedScale=this.scale.copy().domain(domain.map(adjustment)).range(scale.range());return $super(adjustedScale)},_drawGrid:function($super,axis){if(this.grid){$super(axis)}}});Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight");Rickshaw.Graph.Behavior.Series.Highlight=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;var colorSafe={};var activeLine=null;var disabledColor=args.disabledColor||function(seriesColor){return d3.interpolateRgb(seriesColor,d3.rgb("#d8d8d8"))(.8).toString()};this.addHighlightEvents=function(l){l.element.addEventListener("mouseover",function(e){if(activeLine)return;else activeLine=l;self.legend.lines.forEach(function(line){if(l===line){if(self.graph.renderer.unstack&&(line.series.renderer?line.series.renderer.unstack:true)){var seriesIndex=self.graph.series.indexOf(line.series);line.originalIndex=seriesIndex;var series=self.graph.series.splice(seriesIndex,1)[0];self.graph.series.push(series)}return}colorSafe[line.series.name]=colorSafe[line.series.name]||line.series.color;line.series.color=disabledColor(line.series.color)});self.graph.update()},false);l.element.addEventListener("mouseout",function(e){if(!activeLine)return;else activeLine=null;self.legend.lines.forEach(function(line){if(l===line&&line.hasOwnProperty("originalIndex")){var series=self.graph.series.pop();self.graph.series.splice(line.originalIndex,0,series);delete line.originalIndex}if(colorSafe[line.series.name]){line.series.color=colorSafe[line.series.name]}});self.graph.update()},false)};if(this.legend){this.legend.lines.forEach(function(l){self.addHighlightEvents(l)})}};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order");Rickshaw.Graph.Behavior.Series.Order=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;if(typeof window.jQuery=="undefined"){throw"couldn't find jQuery at window.jQuery"}if(typeof window.jQuery.ui=="undefined"){throw"couldn't find jQuery UI at window.jQuery.ui"}jQuery(function(){jQuery(self.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(event,ui){var series=[];jQuery(self.legend.list).find("li").each(function(index,item){if(!item.series)return;series.push(item.series)});for(var i=self.graph.series.length-1;i>=0;i--){self.graph.series[i]=series.shift()}self.graph.update()}});jQuery(self.legend.list).disableSelection()});this.graph.onUpdate(function(){var h=window.getComputedStyle(self.legend.element).height;self.legend.element.style.height=h})};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle");Rickshaw.Graph.Behavior.Series.Toggle=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;this.addAnchor=function(line){var anchor=document.createElement("a");anchor.innerHTML="✔";anchor.classList.add("action");line.element.insertBefore(anchor,line.element.firstChild);anchor.onclick=function(e){if(line.series.disabled){line.series.enable();line.element.classList.remove("disabled")}else{if(this.graph.series.filter(function(s){return!s.disabled}).length<=1)return;line.series.disable();line.element.classList.add("disabled")}self.graph.update()}.bind(this);var label=line.element.getElementsByTagName("span")[0];label.onclick=function(e){var disableAllOtherLines=line.series.disabled;if(!disableAllOtherLines){for(var i=0;idomainX){dataIndex=Math.abs(domainX-data[i].x)0){alignables.forEach(function(el){el.classList.remove("left");el.classList.add("right")});var rightAlignError=this._calcLayoutError(alignables);if(rightAlignError>leftAlignError){alignables.forEach(function(el){el.classList.remove("right");el.classList.add("left")})}}if(typeof this.onRender=="function"){this.onRender(args)}},_calcLayoutError:function(alignables){var parentRect=this.element.parentNode.getBoundingClientRect();var error=0;var alignRight=alignables.forEach(function(el){var rect=el.getBoundingClientRect();if(!rect.width){return}if(rect.right>parentRect.right){error+=rect.right-parentRect.right}if(rect.left=self.previewWidth){frameAfterDrag[0]-=frameAfterDrag[1]-self.previewWidth;frameAfterDrag[1]=self.previewWidth}}self.graphs.forEach(function(graph){var domainScale=d3.scale.linear().interpolate(d3.interpolateNumber).domain([0,self.previewWidth]).range(graph.dataDomain());var windowAfterDrag=[domainScale(frameAfterDrag[0]),domainScale(frameAfterDrag[1])];self.slideCallbacks.forEach(function(callback){callback(graph,windowAfterDrag[0],windowAfterDrag[1])});if(frameAfterDrag[0]===0){windowAfterDrag[0]=undefined}if(frameAfterDrag[1]===self.previewWidth){windowAfterDrag[1]=undefined}graph.window.xMin=windowAfterDrag[0];graph.window.xMax=windowAfterDrag[1];graph.update()})}function onMousedown(){drag.target=d3.event.target;drag.start=self._getClientXFromEvent(d3.event,drag);self.frameBeforeDrag=self.currentFrame.slice();d3.event.preventDefault?d3.event.preventDefault():d3.event.returnValue=false;d3.select(document).on("mousemove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("mouseup.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchmove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("touchend.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",onMouseup)}function onMousedownLeftHandle(datum,index){drag.left=true;onMousedown()}function onMousedownRightHandle(datum,index){drag.right=true;onMousedown()}function onMousedownMiddleHandle(datum,index){drag.left=true;drag.right=true;drag.rigid=true;onMousedown()}function onMouseup(datum,index){d3.select(document).on("mousemove.rickshaw_range_slider_preview",null);d3.select(document).on("mouseup.rickshaw_range_slider_preview",null);d3.select(document).on("touchmove.rickshaw_range_slider_preview",null);d3.select(document).on("touchend.rickshaw_range_slider_preview",null);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",null);delete self.frameBeforeDrag;drag.left=false;drag.right=false;drag.rigid=false}element.select("rect.left_handle").on("mousedown",onMousedownLeftHandle);element.select("rect.right_handle").on("mousedown",onMousedownRightHandle);element.select("rect.middle_handle").on("mousedown",onMousedownMiddleHandle);element.select("rect.left_handle").on("touchstart",onMousedownLeftHandle);element.select("rect.right_handle").on("touchstart",onMousedownRightHandle);element.select("rect.middle_handle").on("touchstart",onMousedownMiddleHandle)},_getClientXFromEvent:function(event,drag){switch(event.type){case"touchstart":case"touchmove":var touchList=event.changedTouches;var touch=null;for(var touchIndex=0;touchIndexyMax)yMax=y});if(!series.length)return;if(series[0].xxMax)xMax=series[series.length-1].x});xMin-=(xMax-xMin)*this.padding.left;xMax+=(xMax-xMin)*this.padding.right;yMin=this.graph.min==="auto"?yMin:this.graph.min||0;yMax=this.graph.max===undefined?yMax:this.graph.max;if(this.graph.min==="auto"||yMin<0){yMin-=(yMax-yMin)*this.padding.bottom}if(this.graph.max===undefined){yMax+=(yMax-yMin)*this.padding.top}return{x:[xMin,xMax],y:[yMin,yMax]}},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var pathNodes=vis.selectAll("path.path").data(data).enter().append("svg:path").classed("path",true).attr("d",this.seriesPathFactory());if(this.stroke){var strokeNodes=vis.selectAll("path.stroke").data(data).enter().append("svg:path").classed("stroke",true).attr("d",this.seriesStrokeFactory())}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=pathNodes[0][i];if(this.stroke)series.stroke=strokeNodes[0][i];this._styleSeries(series);i++},this)},_styleSeries:function(series){var fill=this.fill?series.color:"none";var stroke=this.stroke?series.color:"none";series.path.setAttribute("fill",fill);series.path.setAttribute("stroke",stroke);series.path.setAttribute("stroke-width",this.strokeWidth);if(series.className){d3.select(series.path).classed(series.className,true)}if(series.className&&this.stroke){d3.select(series.stroke).classed(series.className,true)}},configure:function(args){args=args||{};Rickshaw.keys(this.defaults()).forEach(function(key){if(!args.hasOwnProperty(key)){this[key]=this[key]||this.graph[key]||this.defaults()[key];return}if(typeof this.defaults()[key]=="object"){Rickshaw.keys(this.defaults()[key]).forEach(function(k){this[key][k]=args[key][k]!==undefined?args[key][k]:this[key][k]!==undefined?this[key][k]:this.defaults()[key][k]},this)}else{this[key]=args[key]!==undefined?args[key]:this[key]!==undefined?this[key]:this.graph[key]!==undefined?this.graph[key]:this.defaults()[key]}},this)},setStrokeWidth:function(strokeWidth){if(strokeWidth!==undefined){this.strokeWidth=strokeWidth}},setTension:function(tension){if(tension!==undefined){this.tension=tension}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Line");Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack");Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:true,stroke:false,unstack:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar");Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var defaults=Rickshaw.extend($super(),{gapSize:.05,unstack:false});delete defaults.tension;return defaults},initialize:function($super,args){args=args||{};this.gapSize=args.gapSize||this.gapSize;$super(args)},domain:function($super){var domain=$super();var frequentInterval=this._frequentInterval(this.graph.stackedData.slice(-1).shift());domain.x[1]+=Number(frequentInterval.magnitude);return domain},barWidth:function(series){var frequentInterval=this._frequentInterval(series.stack);var barWidth=this.graph.x.magnitude(frequentInterval.magnitude)*(1-this.gapSize);return barWidth},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var barWidth=this.barWidth(series.active()[0]);var barXOffset=0;var activeSeriesCount=series.filter(function(s){return!s.disabled}).length;var seriesBarWidth=this.unstack?barWidth/activeSeriesCount:barWidth;var transform=function(d){var matrix=[1,0,0,d.y<0?-1:1,0,d.y<0?graph.y.magnitude(Math.abs(d.y))*2:0];return"matrix("+matrix.join(",")+")"};series.forEach(function(series){if(series.disabled)return;var barWidth=this.barWidth(series);var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}});return Rickshaw}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.hbs new file mode 100644 index 000000000..ff0fb6023 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.hbs @@ -0,0 +1,29 @@ +{{#if monitor_operations}} + {{#zone "topCss"}} + {{css "css/graph.css"}} + {{/zone}} + +
      +
      +
      +
      + + + + + View Device Analytics + + {{#zone "bottomJs"}} + {{js "js/d3.min.js"}} + {{js "js/rickshaw.min.js"}} + {{js "js/moment.min.js"}} + {{js "js/device-stats.js"}} + {{/zone}} +{{else}} +
      +

      + Stats Loading Failed!

      +
      +{{/if}} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.js new file mode 100644 index 000000000..e7f862207 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.js @@ -0,0 +1,32 @@ +/* + * 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("stats.js"); + var operationModule = require("/app/modules/operation.js").operationModule; + var device = context.unit.params.device; + var monitor_operations; + try { + monitor_operations = JSON.stringify(operationModule.getMonitorOperations(device.type)); + } catch (e) { + log.error("Monitor operation loading failed."); + monitor_operations = null; + } + + return {"monitor_operations": monitor_operations, "device": device}; +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.json new file mode 100644 index 000000000..688e93980 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.device.stats/stats.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.hbs new file mode 100644 index 000000000..94522b0bb --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.hbs @@ -0,0 +1,492 @@ +
      +
      + +
      +
      +

      + Platform Configurations +

      +
      + General and Platform Specific Server Settings for the Tenant +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      + + +
      +
      + +
      +
      + + +
      +
      + + + +
      +
      +
      + + +
      + + +
      + +
      +
      + + +
      +
      + +
      +
      + + +
      + +
      + + +
      +
      +
      + + +
      +
      + +
      +
      + +
      +
      +
      +
      + + + +
      +
      + + +
      + + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      + + + +
      + +
      + + +
      +
      + + + +
      + +
      +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      + + + +
      + +
      +
      + + +
      + +
      + + +
      + +
      + + +
      +
      + + +
      +
      + +
      +
      + +
      +
      +
      +
      + + + +
      +
      +
      + + +
      +
      + + +
      +
      +
      + + +
      +
      + +
      +
      + +
      +
      +
      +
      + +
      +
      +
      +
      + + + +
      +
      +{{#zone "bottomJs"}} + {{js "js/platform-configuration.js"}} +{{/zone}} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.json new file mode 100644 index 000000000..be0496bf6 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/configuration.json @@ -0,0 +1,4 @@ +{ + "version" : "1.0.0", + "extends": "cdmf.unit.platform.configuration" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/public/js/platform-configuration.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/public/js/platform-configuration.js new file mode 100644 index 000000000..41123e12a --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.platform.configuration/public/js/platform-configuration.js @@ -0,0 +1,856 @@ +/* + * 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. + */ + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param inputString Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +function inputIsValid(regExp, inputString) { + return regExp.test(inputString); +} + +/** + * Checks if an email address has the valid format or not. + * + * @param email Email address + * @returns {boolean} true if email has the valid format, otherwise false. + */ +function emailIsValid(email) { + var regExp = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; + return regExp.test(email); +} + +var notifierTypeConstants = { + "LOCAL": "1", + "GCM": "2" +}; +// Constants to define platform types available +var platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" +}; + +var responseCodes = { + "CREATED": "Created", + "SUCCESS": "201", + "INTERNAL_SERVER_ERROR": "Internal Server Error" +}; + +var configParams = { + "NOTIFIER_TYPE": "notifierType", + "NOTIFIER_FREQUENCY": "notifierFrequency", + "GCM_API_KEY": "gcmAPIKey", + "GCM_SENDER_ID": "gcmSenderId", + "ANDROID_EULA": "androidEula", + "IOS_EULA": "iosEula", + "CONFIG_COUNTRY": "configCountry", + "CONFIG_STATE": "configState", + "CONFIG_LOCALITY": "configLocality", + "CONFIG_ORGANIZATION": "configOrganization", + "CONFIG_ORGANIZATION_UNIT": "configOrganizationUnit", + "MDM_CERT_PASSWORD": "MDMCertPassword", + "MDM_CERT_TOPIC_ID": "MDMCertTopicID", + "APNS_CERT_PASSWORD": "APNSCertPassword", + "MDM_CERT": "MDMCert", + "MDM_CERT_NAME": "MDMCertName", + "APNS_CERT": "APNSCert", + "APNS_CERT_NAME": "APNSCertName", + "ORG_DISPLAY_NAME": "organizationDisplayName", + "GENERAL_EMAIL_HOST": "emailHost", + "GENERAL_EMAIL_PORT": "emailPort", + "GENERAL_EMAIL_USERNAME": "emailUsername", + "GENERAL_EMAIL_PASSWORD": "emailPassword", + "GENERAL_EMAIL_SENDER_ADDRESS": "emailSender", + "GENERAL_EMAIL_TEMPLATE": "emailTemplate", + "COMMON_NAME": "commonName", + "KEYSTORE_PASSWORD": "keystorePassword", + "PRIVATE_KEY_PASSWORD": "privateKeyPassword", + "BEFORE_EXPIRE": "beforeExpire", + "AFTER_EXPIRE": "afterExpire", + "WINDOWS_EULA": "windowsLicense" +}; + +$(document).ready(function () { + $("#gcm-inputs").hide(); + tinymce.init({ + selector: "textarea", + theme: "modern", + plugins: [ + "advlist autolink lists link image charmap print preview anchor", + "searchreplace visualblocks code fullscreen", + "insertdatetime image table contextmenu paste" + ], + toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" + }); + + var getAndroidConfigAPI = "/mdm-android-agent/configuration"; + var getGeneralConfigAPI = "/devicemgt_admin/configuration"; + var getIosConfigAPI = "/ios/configuration"; + var getWindowsConfigAPI = "/mdm-windows-agent/services/configuration"; + + /** + * Following requests would execute + * on page load event of platform configuration page in WSO2 EMM Console. + * Upon receiving the response, the parameters will be set to the fields, + * in case those configurations are already set. + */ + invokerUtil.get( + getAndroidConfigAPI, + + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if(config.name == configParams["NOTIFIER_TYPE"]){ + $("#android-config-notifier").val(config.value); + if(config.value != notifierTypeConstants["GCM"] ) { + $("#gcm-inputs").hide(); + }else{ + $("#gcm-inputs").show(); + } + } else if(config.name == configParams["NOTIFIER_FREQUENCY"]){ + $("input#android-config-notifier-frequency").val(config.value); + } else if(config.name == configParams["GCM_API_KEY"]){ + $("input#android-config-gcm-api-key").val(config.value); + } else if(config.name == configParams["GCM_SENDER_ID"]){ + $("input#android-config-gcm-sender-id").val(config.value); + } else if(config.name == configParams["ANDROID_EULA"]){ + $("#android-eula").val(config.value); + } + } + } + + }, function () { + + } + ); + + invokerUtil.get( + getGeneralConfigAPI, + + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if(config.name == configParams["NOTIFIER_FREQUENCY"]){ + $("input#monitoring-config-frequency").val(config.value); + } + /*if(config.name == configParams["GENERAL_EMAIL_HOST"]){ + $("input#email-config-host").val(config.value); + } else if(config.name == configParams["GENERAL_EMAIL_PORT"]){ + $("input#email-config-port").val(config.value); + } else if(config.name == configParams["GENERAL_EMAIL_USERNAME"]){ + $("input#email-config-username").val(config.value); + } else if(config.name == configParams["GENERAL_EMAIL_PASSWORD"]){ + $("input#email-config-password").val(config.value); + } else if(config.name == configParams["GENERAL_EMAIL_SENDER_ADDRESS"]){ + $("input#email-config-sender-email").val(config.value); + } else if(config.name == configParams["GENERAL_EMAIL_TEMPLATE"]){ + $("input#email-config-template").val(config.value); + }*/ + } + } + + }, function () { + + } + ); + + invokerUtil.get( + getIosConfigAPI, + + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if(config.name == configParams["CONFIG_COUNTRY"]){ + $("input#ios-config-country").val(config.value); + } else if(config.name == configParams["CONFIG_STATE"]){ + $("input#ios-config-state").val(config.value); + } else if(config.name == configParams["CONFIG_LOCALITY"]){ + $("input#ios-config-locality").val(config.value); + } else if(config.name == configParams["CONFIG_ORGANIZATION"]){ + $("input#ios-config-organization").val(config.value); + } else if(config.name == configParams["CONFIG_ORGANIZATION_UNIT"]){ + $("input#ios-config-organization-unit").val(config.value); + } else if(config.name == configParams["MDM_CERT_PASSWORD"]){ + $("input#ios-config-mdm-certificate-password").val(config.value); + } else if(config.name == configParams["MDM_CERT_TOPIC_ID"]){ + $("input#ios-config-mdm-certificate-topic-id").val(config.value); + } else if(config.name == configParams["APNS_CERT_PASSWORD"]){ + $("input#ios-config-apns-certificate-password").val(config.value); + } else if(config.name == configParams["MDM_CERT_NAME"]){ + $("#mdm-cert-file-name").html(config.value); + } else if(config.name == configParams["APNS_CERT_NAME"]){ + $("#apns-cert-file-name").html(config.value); + } else if(config.name == configParams["ORG_DISPLAY_NAME"]){ + $("input#ios-org-display-name").val(config.value); + } else if(config.name == configParams["IOS_EULA"]){ + $("#ios-eula").val(config.value); + } + } + } + + }, function () { + + } + ); + + invokerUtil.get( + getWindowsConfigAPI, + + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if(config.name == configParams["NOTIFIER_FREQUENCY"]) { + $("input#windows-config-notifier-frequency").val(config.value); + } else if(config.name == configParams["WINDOWS_EULA"]) { + $("#windows-eula").val(config.value); + } + } + } + + }, function () { + + } + ); + + + $("select.select2[multiple=multiple]").select2({ + tags : true + }); + + $("#android-config-notifier").change(function() { + var notifierType = $("#android-config-notifier").find("option:selected").attr("value"); + if(notifierType != notifierTypeConstants["GCM"] ) { + $("#gcm-inputs").hide(); + $("#local-inputs").show(); + }else{ + $("#local-inputs").hide(); + $("#gcm-inputs").show(); + } + }); + /** + * Following click function would execute + * when a user clicks on "Save" button + * on Android platform configuration page in WSO2 EMM Console. + */ + $("button#save-android-btn").click(function() { + var notifierType = $("#android-config-notifier").find("option:selected").attr("value"); + var notifierFrequency = $("input#android-config-notifier-frequency").val(); + var gcmAPIKey = $("input#android-config-gcm-api-key").val(); + var gcmSenderId = $("input#android-config-gcm-sender-id").val(); + var androidLicense = tinymce.get('android-eula').getContent(); + + var errorMsgWrapper = "#android-config-error-msg"; + var errorMsg = "#android-config-error-msg span"; + if (!notifierFrequency) { + $(errorMsg).text("Notifier frequency is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!$.isNumeric(notifierFrequency)) { + $(errorMsg).text("Provided notifier frequency is invalid. Please check."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (notifierType == notifierTypeConstants["GCM"] && !gcmAPIKey) { + $(errorMsg).text("GCM API Key is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (notifierType == notifierTypeConstants["GCM"] && !gcmSenderId) { + $(errorMsg).text("GCM Sender ID is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + + var addConfigFormData = {}; + var configList = new Array(); + + var type = { + "name": configParams["NOTIFIER_TYPE"], + "value": notifierType, + "contentType": "text" + }; + + var frequency = { + "name": configParams["NOTIFIER_FREQUENCY"], + "value": notifierFrequency, + "contentType": "text" + }; + + var gcmKey = { + "name": configParams["GCM_API_KEY"], + "value": gcmAPIKey, + "contentType": "text" + }; + + var gcmId = { + "name": configParams["GCM_SENDER_ID"], + "value": gcmSenderId, + "contentType": "text" + }; + + var androidEula = { + "name": configParams["ANDROID_EULA"], + "value": androidLicense, + "contentType": "text" + }; + + configList.push(type); + configList.push(frequency); + configList.push(androidEula); + if (notifierType == notifierTypeConstants["GCM"]) { + configList.push(gcmKey); + configList.push(gcmId); + } + + addConfigFormData.type = platformTypeConstants["ANDROID"]; + addConfigFormData.configuration = configList; + + var addConfigAPI = "/mdm-android-agent/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.responseCode == responseCodes["CREATED"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function () { + $(errorMsg).text("An unexpected error occurred."); + $(errorMsgWrapper).removeClass("hidden"); + } + ); + } + }); + + /** + * Following click function would execute + * when a user clicks on "Save" button + * on General platform configuration page in WSO2 EMM Console. + */ + $("button#save-general-btn").click(function() { + var notifierFrequency = $("input#monitoring-config-frequency").val(); + /*var emailHost = $("input#email-config-host").val(); + var emailPort = $("input#email-config-port").val(); + var emailUsername = $("input#email-config-username").val(); + var emailPassword = $("input#email-config-password").val(); + var emailSenderAddress = $("input#email-config-sender-email").val(); + var emailTemplate = $("input#email-config-template").val();*/ + + var errorMsgWrapper = "#email-config-error-msg"; + var errorMsg = "#email-config-error-msg span"; + + if (!notifierFrequency) { + $(errorMsg).text("Monitoring frequency is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!$.isNumeric(notifierFrequency)) { + $(errorMsg).text("Provided monitoring frequency is invalid. It must be a number."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + + var addConfigFormData = {}; + var configList = new Array(); + + var monitorFrequency = { + "name": configParams["NOTIFIER_FREQUENCY"], + "value": notifierFrequency, + "contentType": "text" + }; + + /*if (!emailHost) { + $(errorMsg).text("Email Host is a required field. It cannot be empty."); + //$(errorMsgWrapper).removeClass("hidden"); + } else if (!notifierFrequency) { + $(errorMsg).text("Monitoring frequency is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!$.isNumeric(notifierFrequency)) { + $(errorMsg).text("Provided monitoring frequency is invalid. It must be a number."); + $(errorMsgWrapper).removeClass("hidden"); + }else if (!emailPort) { + $(errorMsg).text("Email Port is a required field. It cannot be empty."); + //$(errorMsgWrapper).removeClass("hidden"); + } else if (!emailUsername) { + $(errorMsg).text("Username is a required field. It cannot be empty."); + //$(errorMsgWrapper).removeClass("hidden"); + } else if (!emailPassword) { + $(errorMsg).text("Password is a required field. It cannot be empty."); + //$(errorMsgWrapper).removeClass("hidden"); + } else if (!emailSenderAddress) { + $(errorMsg).text("Sender Email Address is a required field. It cannot be empty."); + //$(errorMsgWrapper).removeClass("hidden"); + } else if (!emailIsValid(emailSenderAddress)) { + $(errorMsg).text("Provided sender email is invalid. Please check."); + //$(errorMsgWrapper).removeClass("hidden"); + } */ + + /*var host = { + "name": configParams["GENERAL_EMAIL_HOST"], + "value": emailHost, + "contentType": "text" + }; + + var port = { + "name": configParams["GENERAL_EMAIL_PORT"], + "value": emailPort, + "contentType": "text" + }; + + var username = { + "name": configParams["GENERAL_EMAIL_USERNAME"], + "value": emailUsername, + "contentType": "text" + }; + + var password = { + "name": configParams["GENERAL_EMAIL_PASSWORD"], + "value": emailPassword, + "contentType": "text" + }; + + var sender = { + "name": configParams["GENERAL_EMAIL_SENDER_ADDRESS"], + "value": emailSenderAddress, + "contentType": "text" + }; + + var template = { + "name": configParams["GENERAL_EMAIL_TEMPLATE"], + "value": emailTemplate, + "contentType": "text" + };*/ + + configList.push(monitorFrequency); + /*configList.push(host); + configList.push(port); + configList.push(username); + configList.push(password); + configList.push(sender); + configList.push(template);*/ + + addConfigFormData.configuration = configList; + + var addConfigAPI = "/devicemgt_admin/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.statusCode == responseCodes["SUCCESS"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function () { + $(errorMsg).text("An unexpected error occurred."); + $(errorMsgWrapper).removeClass("hidden"); + } + ); + } + }); + + var errorMsgWrapper = "#ios-config-error-msg"; + var errorMsg = "#ios-config-error-msg span"; + var fileTypes = ['pfx']; + var notSupportedError = false; + + var base64MDMCert = ""; + var fileInputMDMCert = $('#ios-config-mdm-certificate'); + var fileNameMDMCert = ""; + var invalidFormatMDMCert = false; + + var base64APNSCert = ""; + var fileInputAPNSCert = $('#ios-config-apns-certificate'); + var fileNameAPNSCert = ""; + var invalidFormatAPNSCert = false; + + $(fileInputMDMCert).change(function() { + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + notSupportedError = true; + return; + } + + var file = fileInputMDMCert[0].files[0]; + fileNameMDMCert = file.name; + var extension = file.name.split('.').pop().toLowerCase(), + isSuccess = fileTypes.indexOf(extension) > -1; + + if (isSuccess) { + var fileReader = new FileReader(); + fileReader.onload = function(event) { + base64MDMCert = event.target.result; + }; + fileReader.readAsDataURL(file); + invalidFormatMDMCert = false; + } else { + base64MDMCert = ""; + invalidFormatMDMCert = true; + } + }); + + $(fileInputAPNSCert).change(function() { + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + notSupportedError = true; + return; + } + + var file = fileInputAPNSCert[0].files[0]; + fileNameAPNSCert = file.name; + var extension = file.name.split('.').pop().toLowerCase(), + isSuccess = fileTypes.indexOf(extension) > -1; + + if (isSuccess) { + var fileReader = new FileReader(); + fileReader.onload = function(event) { + base64APNSCert = event.target.result; + }; + fileReader.readAsDataURL(file); + invalidFormatAPNSCert = false; + } else { + base64MDMCert = ""; + invalidFormatAPNSCert = true; + } + }); + + $("button#save-ios-btn").click(function() { + + var configCountry = $("#ios-config-country").val(); + var configState = $("#ios-config-state").val(); + var configLocality = $("#ios-config-locality").val(); + var configOrganization = $("#ios-config-organization").val(); + var configOrganizationUnit = $("#ios-config-organization-unit").val(); + var MDMCertPassword = $("#ios-config-mdm-certificate-password").val(); + var MDMCertTopicID = $("#ios-config-mdm-certificate-topic-id").val(); + var APNSCertPassword = $("#ios-config-apns-certificate-password").val(); + var configOrgDisplayName = $("#ios-org-display-name").val(); + var iosLicense = tinymce.get('ios-eula').getContent(); + + if (!configCountry) { + $(errorMsg).text("SCEP country is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configState) { + $(errorMsg).text("SCEP state is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configLocality) { + $(errorMsg).text("SCEP locality is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configOrganization) { + $(errorMsg).text("SCEP organization is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configOrganizationUnit) { + $(errorMsg).text("SCEP organization unit is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!MDMCertPassword) { + $(errorMsg).text("MDM certificate password is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!MDMCertTopicID) { + $(errorMsg).text("MDM certificate topic ID is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!APNSCertPassword) { + $(errorMsg).text("APNS certificate password is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if(notSupportedError) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (invalidFormatMDMCert) { + $(errorMsg).text("MDM certificate needs to be in pfx format."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (base64MDMCert == '') { + $(errorMsg).text("MDM certificate is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (invalidFormatAPNSCert) { + $(errorMsg).text("APNS certificate needs to be in pfx format."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (base64APNSCert == '') { + $(errorMsg).text("APNS certificate is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configOrgDisplayName) { + $(errorMsg).text("Organization display name is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } + + var addConfigFormData = {}; + var configList = new Array(); + + var configCountry = { + "name": configParams["CONFIG_COUNTRY"], + "value": configCountry, + "contentType": "text" + }; + + var configState = { + "name": configParams["CONFIG_STATE"], + "value": configState, + "contentType": "text" + }; + + var configLocality = { + "name": configParams["CONFIG_LOCALITY"], + "value": configLocality, + "contentType": "text" + }; + + var configOrganization = { + "name": configParams["CONFIG_ORGANIZATION"], + "value": configOrganization, + "contentType": "text" + }; + + var configOrganizationUnit = { + "name": configParams["CONFIG_ORGANIZATION_UNIT"], + "value": configOrganizationUnit, + "contentType": "text" + }; + + var MDMCertPassword = { + "name": configParams["MDM_CERT_PASSWORD"], + "value": MDMCertPassword, + "contentType": "text" + }; + + var MDMCertTopicID = { + "name": configParams["MDM_CERT_TOPIC_ID"], + "value": MDMCertTopicID, + "contentType": "text" + }; + + var APNSCertPassword = { + "name": configParams["APNS_CERT_PASSWORD"], + "value": APNSCertPassword, + "contentType": "text" + }; + + var paramBase64MDMCert = { + "name": configParams["MDM_CERT"], + "value": base64MDMCert, + "contentType": "text" + }; + + var MDMCertName = { + "name": configParams["MDM_CERT_NAME"], + "value": fileNameMDMCert, + "contentType": "text" + }; + + var paramBase64APNSCert = { + "name": configParams["APNS_CERT"], + "value": base64APNSCert, + "contentType": "text" + }; + + var APNSCertName = { + "name": configParams["APNS_CERT_NAME"], + "value": fileNameAPNSCert, + "contentType": "text" + }; + + var paramOrganizationDisplayName = { + "name": configParams["ORG_DISPLAY_NAME"], + "value": configOrgDisplayName, + "contentType": "text" + }; + + var iosEula = { + "name": configParams["IOS_EULA"], + "value": iosLicense, + "contentType": "text" + }; + + configList.push(configCountry); + configList.push(configState); + configList.push(configLocality); + configList.push(configOrganization); + configList.push(configOrganizationUnit); + configList.push(MDMCertPassword); + configList.push(MDMCertTopicID); + configList.push(APNSCertPassword); + configList.push(paramBase64MDMCert); + configList.push(MDMCertName); + configList.push(paramBase64APNSCert); + configList.push(APNSCertName); + configList.push(paramOrganizationDisplayName); + configList.push(iosEula); + + addConfigFormData.type = platformTypeConstants["IOS"]; + addConfigFormData.configuration = configList; + + var addConfigAPI = "/ios/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.responseCode == responseCodes["CREATED"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 400) { + $(errorMsg).text("Configurations cannot be empty."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function () { + $(errorMsg).text("An unexpected error occurred."); + $(errorMsgWrapper).removeClass("hidden"); + } + ); + + }); + + var errorMsgWrapper = "#windows-config-error-msg"; + var errorMsg = "#windows-config-error-msg span"; + var fileTypes = ['jks']; + var notSupportedError = false; + + var base64WindowsMDMCert = ""; + var fileInputWindowsMDMCert = $('#windows-config-mdm-certificate'); + var fileNameWindowsMDMCert = ""; + var invalidFormatWindowsMDMCert = false; + + $(fileInputWindowsMDMCert).change(function() { + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + notSupportedError = true; + return; + } + + var file = fileInputWindowsMDMCert[0].files[0]; + fileNameWindowsMDMCert = file.name; + var extension = file.name.split('.').pop().toLowerCase(), + isSuccess = fileTypes.indexOf(extension) > -1; + + if (isSuccess) { + var fileReader = new FileReader(); + fileReader.onload = function(event) { + base64WindowsMDMCert = event.target.result; + }; + fileReader.readAsDataURL(file); + invalidFormatWindowsMDMCert = false; + } else { + base64MDMCert = ""; + invalidFormatWindowsMDMCert = true; + } + }); + + $("button#save-windows-btn").click(function() { + + var notifierFrequency = $("#windows-config-notifier-frequency").val(); + var windowsLicense = tinymce.get('windows-eula').getContent(); + + if (!notifierFrequency) { + $(errorMsg).text("Notifier Frequency is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!windowsLicense) { + $(errorMsg).text("License is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if(!$.isNumeric(notifierFrequency)){ + $(errorMsg).text("Provided Notifier frequency is invalid. It must be a number."); + $(errorMsgWrapper).removeClass("hidden"); + } + + var addConfigFormData = {}; + var configList = new Array(); + + var paramNotifierFrequency = { + "name": configParams["NOTIFIER_FREQUENCY"], + "value": notifierFrequency, + "contentType": "text" + }; + + var windowsEula = { + "name": configParams["WINDOWS_EULA"], + "value": windowsLicense, + "contentType": "text" + }; + + configList.push(paramNotifierFrequency); + configList.push(windowsEula); + + addConfigFormData.type = platformTypeConstants["WINDOWS"]; + addConfigFormData.configuration = configList; + + var addConfigAPI = "/mdm-windows-agent/services/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.responseCode == responseCodes["CREATED"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 400) { + $(errorMsg).text("Configurations cannot be empty."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function () { + $(errorMsg).text("An unexpected error occurred."); + $(errorMsgWrapper).removeClass("hidden"); + } + ); + + }); +}); + +// Start of HTML embedded invoke methods +var showAdvanceOperation = function (operation, button) { + $(button).addClass('selected'); + $(button).siblings().removeClass('selected'); + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="' + operation + '"]').show(); + $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide(); +}; diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.hbs new file mode 100644 index 000000000..441828918 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.hbs @@ -0,0 +1,246 @@ +{{#zone "topCss"}} + {{css "css/codemirror.css"}} +{{/zone}} +
      +
      + + + + + + + + + +
      +
      +

      EDIT POLICY

      +
      +
      +
      +
      +
      +

      Step 1: Edit current profile

      +
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      + +
      +
      +
      +
      + + + +
      +
      +{{#zone "bottomJs"}} + {{js "js/codemirror.js"}} + {{js "js/sql.js"}} + {{js "js/policy-edit.js"}} +{{/zone}} + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.js new file mode 100644 index 000000000..36b130ca0 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.js @@ -0,0 +1,25 @@ +/* + * 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("policy-view-edit-unit backend js"); + log.debug("calling policy-view-edit-unit"); + var userModule = require("/app/modules/user.js").userModule; + context.roles = userModule.getRoles().content; + return context; +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.json new file mode 100644 index 000000000..fd2590129 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/edit.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/css/codemirror.css b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/css/codemirror.css new file mode 100644 index 000000000..e749a5211 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/css/codemirror.css @@ -0,0 +1,342 @@ +/* + * 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. + */ + +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; + left: -30px; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +@-moz-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@-webkit-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +div.CodeMirror-overwrite div.CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + height: 100%; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; + left: -30px; +} +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + border-right: none; + width: 0; +} + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror ::selection { background: #d7d4f0; } +.CodeMirror ::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/codemirror.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/codemirror.js new file mode 100644 index 000000000..20f3f95ed --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/codemirror.js @@ -0,0 +1,8720 @@ +/* + * 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. + */ + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + module.exports = mod(); + else if (typeof define == "function" && define.amd) // AMD + return define([], mod); + else // Plain browser env + this.CodeMirror = mod(); +})(function() { + "use strict"; + + // BROWSER SNIFFING + + // Kludges for bugs and behavior differences that can't be feature + // detected are enabled based on userAgent etc sniffing. + + var gecko = /gecko\/\d/i.test(navigator.userAgent); + var ie_upto10 = /MSIE \d/.test(navigator.userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); + var ie = ie_upto10 || ie_11up; + var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); + var webkit = /WebKit\//.test(navigator.userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); + var chrome = /Chrome\//.test(navigator.userAgent); + var presto = /Opera\//.test(navigator.userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); + var phantom = /PhantomJS/.test(navigator.userAgent); + + var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + // This is woefully incomplete. Suggestions for alternative methods welcome. + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); + var mac = ios || /Mac/.test(navigator.platform); + var windows = /win/i.test(navigator.platform); + + var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); + if (presto_version) presto_version = Number(presto_version[1]); + if (presto_version && presto_version >= 15) { presto = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); + var captureRightClick = gecko || (ie && ie_version >= 9); + + // Optimize some code when these features are not used. + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + // EDITOR CONSTRUCTOR + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options ? copyObj(options) : {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + setGuttersForLineNumbers(options); + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(doc, options.mode); + this.doc = doc; + + var input = new CodeMirror.inputStyles[options.inputStyle](this); + var display = this.display = new Display(place, doc, input); + display.wrapper.CodeMirror = this; + updateGutters(this); + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + if (options.autofocus && !mobile) display.input.focus(); + initScrollbars(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + }; + + var cm = this; + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); + + registerEventHandlers(this); + ensureGlobalHandlers(); + + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); + + if ((options.autofocus && !mobile) || cm.hasFocus()) + setTimeout(bind(onFocus, this), 20); + else + onBlur(this); + + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](this, options[opt], Init); + maybeUpdateLineNumberWidth(this); + if (options.finishInit) options.finishInit(this); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + endOperation(this); + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + display.lineDiv.style.textRendering = "auto"; + } + + // DISPLAY CONSTRUCTOR + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc, input) { + var d = this; + this.input = input; + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.scrollbarFiller.setAttribute("cm-not-content", "true"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + d.gutterFiller.setAttribute("cm-not-content", "true"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = elt("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + d.sizerWidth = null; + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; + + if (place) { + if (place.appendChild) place.appendChild(d.wrapper); + else place(d.wrapper); + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + d.reportedViewFrom = d.reportedViewTo = doc.first; + // Information about the rendered lines. + d.view = []; + d.renderedView = null; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastWrapHeight = d.lastWrapWidth = 0; + d.updateLineNumbers = null; + + d.nativeBarWidth = d.barHeight = d.barWidth = 0; + d.scrollbarsClipped = false; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + + d.activeTouch = null; + + input.init(d); + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + cm.display.sizerWidth = null; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function(){updateScrollbars(cm);}, 100); + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function(line) { + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + else + return widgetsHeight + th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + updateGutterSpace(cm); + } + + function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth; + cm.display.sizer.style.marginLeft = width + "px"; + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(0, true); + len -= cur.text.length - found.from.ch; + cur = found.to.line; + len += cur.text.length - found.to.ch; + } + return len; + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(found, 1); + } + } + + // SCROLLBARS + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth; + var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + }; + } + + function NativeScrollbars(place, scroll, cm) { + this.cm = cm; + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + place(vert); place(horiz); + + on(vert, "scroll", function() { + if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); + }); + on(horiz, "scroll", function() { + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); + }); + + this.checkedOverlay = false; + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; + } + + NativeScrollbars.prototype = copyObj({ + update: function(measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + var sWidth = measure.nativeBarWidth; + + if (needsV) { + this.vert.style.display = "block"; + this.vert.style.bottom = needsH ? sWidth + "px" : "0"; + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + } else { + this.vert.style.display = ""; + this.vert.firstChild.style.height = "0"; + } + + if (needsH) { + this.horiz.style.display = "block"; + this.horiz.style.right = needsV ? sWidth + "px" : "0"; + this.horiz.style.left = measure.barLeft + "px"; + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.firstChild.style.width = + (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + } else { + this.horiz.style.display = ""; + this.horiz.firstChild.style.width = "0"; + } + + if (!this.checkedOverlay && measure.clientHeight > 0) { + if (sWidth == 0) this.overlayHack(); + this.checkedOverlay = true; + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; + }, + setScrollLeft: function(pos) { + if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; + }, + setScrollTop: function(pos) { + if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; + }, + overlayHack: function() { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + this.horiz.style.minHeight = this.vert.style.minWidth = w; + var self = this; + var barMouseDown = function(e) { + if (e_target(e) != self.vert && e_target(e) != self.horiz) + operation(self.cm, onMouseDown)(e); + }; + on(this.vert, "mousedown", barMouseDown); + on(this.horiz, "mousedown", barMouseDown); + }, + clear: function() { + var parent = this.horiz.parentNode; + parent.removeChild(this.horiz); + parent.removeChild(this.vert); + } + }, NativeScrollbars.prototype); + + function NullScrollbars() {} + + NullScrollbars.prototype = copyObj({ + update: function() { return {bottom: 0, right: 0}; }, + setScrollLeft: function() {}, + setScrollTop: function() {}, + clear: function() {} + }, NullScrollbars.prototype); + + CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; + + function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear(); + if (cm.display.scrollbars.addClass) + rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function() { + if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); + }); + node.setAttribute("cm-not-content", "true"); + }, function(pos, axis) { + if (axis == "horizontal") setScrollLeft(cm, pos); + else setScrollTop(cm, pos); + }, cm); + if (cm.display.scrollbars.addClass) + addClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + function updateScrollbars(cm, measure) { + if (!measure) measure = measureForScrollbars(cm); + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; + updateScrollbarsInner(cm, measure); + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + updateHeightsInViewport(cm); + updateScrollbarsInner(cm, measureForScrollbars(cm)); + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + } + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbarsInner(cm, measure) { + var d = cm.display; + var sizes = d.scrollbars.update(measure); + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = sizes.bottom + "px"; + d.scrollbarFiller.style.width = sizes.right + "px"; + } else d.scrollbarFiller.style.display = ""; + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sizes.bottom + "px"; + d.gutterFiller.style.width = measure.gutterWidth + "px"; + } else d.gutterFiller.style.display = ""; + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewport may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + if (ensureFrom < from) { + from = ensureFrom; + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); + to = ensureTo; + } + } + return {from: from, to: Math.max(to, from + 1)}; + } + + // LINE NUMBERS + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + if (cm.options.fixedGutter && view[i].gutter) + view[i].gutter.style.left = left; + var align = view[i].alignable; + if (align) for (var j = 0; j < align.length; j++) + align[j].style.left = left; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm); + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + } + + // DISPLAY DRAWING + + function DisplayUpdate(cm, viewport, force) { + var display = cm.display; + + this.viewport = viewport; + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport); + this.editorIsHidden = !display.wrapper.offsetWidth; + this.wrapperHeight = display.wrapper.clientHeight; + this.wrapperWidth = display.wrapper.clientWidth; + this.oldDisplayWidth = displayWidth(cm); + this.force = force; + this.dims = getDimensions(cm); + this.events = []; + } + + DisplayUpdate.prototype.signal = function(emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments); + }; + DisplayUpdate.prototype.finish = function() { + for (var i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]); + }; + + function maybeClipScrollbars(cm) { + var display = cm.display; + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; + display.heightForcer.style.height = scrollGap(cm) + "px"; + display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; + display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; + display.scrollbarsClipped = true; + } + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc; + + if (update.editorIsHidden) { + resetView(cm); + return false; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + return false; + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm); + update.dims = getDimensions(cm); + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, update.visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + return false; + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt(); + if (toUpdate > 4) display.lineDiv.style.display = "none"; + patchDisplay(cm, display.updateLineNumbers, update.dims); + if (toUpdate > 4) display.lineDiv.style.display = ""; + display.renderedView = display.view; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + display.gutters.style.height = 0; + + if (different) { + display.lastWrapHeight = update.wrapperHeight; + display.lastWrapWidth = update.wrapperWidth; + startWorker(cm, 400); + } + + display.updateLineNumbers = null; + + return true; + } + + function postUpdateDisplay(cm, update) { + var force = update.force, viewport = update.viewport; + for (var first = true;; first = false) { + if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) { + force = true; + } else { + force = false; + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + break; + } + if (!updateDisplayIfNeeded(cm, update)) break; + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + } + + update.signal(cm, "update", cm); + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + } + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm); + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + update.finish(); + } + } + + function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px"; + var total = measure.docHeight + cm.display.barHeight; + cm.display.heightForcer.style.top = total + "px"; + cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height; + if (cur.hidden) continue; + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + } + var diff = cur.line.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + updateWidgetHeight(cur.rest[j]); + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + line.widgets[i].height = line.widgets[i].node.offsetHeight; + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + var gutterLeft = d.gutters.clientLeft; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; + width[cm.options.gutters[i]] = n.clientWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth}; + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + node.style.display = "none"; + else + node.parentNode.removeChild(node); + return next; + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) cur = rm(cur); + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) cur = rm(cur); + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") updateLineText(cm, lineView); + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); + else if (type == "class") updateLineClasses(lineView); + else if (type == "widget") updateLineWidgets(cm, lineView, dims); + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + lineView.text.parentNode.replaceChild(lineView.node, lineView.text); + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + } + return lineView.node; + } + + function updateLineBackground(lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) cls += " CodeMirror-linebackground"; + if (lineView.background) { + if (cls) lineView.background.className = cls; + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built; + } + return buildLineContent(cm, lineView); + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) lineView.node = built.pre; + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(lineView) { + updateLineBackground(lineView); + if (lineView.line.wrapClass) + ensureLineWrapped(lineView).className = lineView.line.wrapClass; + else if (lineView.node != lineView.text) + lineView.node.className = ""; + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + + "px; width: " + dims.gutterTotalWidth + "px"); + cm.display.input.setUneditable(gutterWrap); + wrap.insertBefore(gutterWrap, lineView.text); + if (lineView.line.gutterClass) + gutterWrap.className += " " + lineView.line.gutterClass; + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + cm.display.lineNumInnerWidth + "px")); + if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + } + } + } + + function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) lineView.alignable = null; + for (var node = lineView.node.firstChild, next; node; node = next) { + var next = node.nextSibling; + if (node.className == "CodeMirror-linewidget") + lineView.node.removeChild(node); + } + insertLineWidgets(cm, lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) lineView.bgClass = built.bgClass; + if (built.textClass) lineView.textClass = built.textClass; + + updateLineClasses(lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(cm, lineView, dims); + return lineView.node; + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); + } + + function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) return; + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); + positionLineWidget(widget, node, lineView, dims); + cm.display.input.setUneditable(node); + if (allowAbove && widget.above) + wrap.insertBefore(node, lineView.gutter || lineView.text); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // POSITION OBJECT + + // A Pos instance represents a position within the text. + var Pos = CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; + + function copyPos(x) {return Pos(x.line, x.ch);} + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } + + // INPUT HANDLING + + function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + } + + function isReadOnly(cm) { + return cm.options.readOnly || cm.doc.cantEdit; + } + + // This will be set to an array of strings when copying, so that, + // when pasting, we know what kind of selections the copied text + // was made out of. + var lastCopied = null; + + function applyTextInput(cm, inserted, deleted, sel) { + var doc = cm.doc; + cm.display.shift = false; + if (!sel) sel = doc.sel; + + var textLines = splitLines(inserted), multiPaste = null; + // When pasing N lines into N selections, insert one line per selection + if (cm.state.pasteIncoming && sel.ranges.length > 1) { + if (lastCopied && lastCopied.join("\n") == inserted) + multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); + else if (textLines.length == sel.ranges.length) + multiPaste = map(textLines, function(l) { return [l]; }); + } + + // Normal behavior is to insert the new text into every selection + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + var from = range.from(), to = range.to(); + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + from = Pos(from.line, from.ch - deleted); + else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + } + var updateInput = cm.curOp.updateInput; + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, + origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + // When an 'electric' character is inserted, immediately trigger a reindent + if (inserted && !cm.state.pasteIncoming && cm.options.electricChars && + cm.options.smartIndent && range.head.ch < 100 && + (!i || sel.ranges[i - 1].head.line != range.head.line)) { + var mode = cm.getModeAt(range.head); + var end = changeEnd(changeEvent); + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indentLine(cm, end.line, "smart"); + break; + } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) + indentLine(cm, end.line, "smart"); + } + } + } + ensureCursorVisible(cm); + cm.curOp.updateInput = updateInput; + cm.curOp.typing = true; + cm.state.pasteIncoming = cm.state.cutIncoming = false; + } + + function copyableRanges(cm) { + var text = [], ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; + ranges.push(lineRange); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); + } + return {text: text, ranges: ranges}; + } + + function disableBrowserMagic(field) { + field.setAttribute("autocorrect", "off"); + field.setAttribute("autocapitalize", "off"); + field.setAttribute("spellcheck", "false"); + } + + // TEXTAREA INPUT STYLE + + function TextareaInput(cm) { + this.cm = cm; + // See input.poll and input.reset + this.prevInput = ""; + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false; + // Self-resetting timeout for the poller + this.polling = new Delayed(); + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false; + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false; + }; + + function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) te.style.width = "1000px"; + else te.setAttribute("wrap", "off"); + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) te.style.border = "1px solid black"; + disableBrowserMagic(te); + return div; + } + + TextareaInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = this.cm; + + // Wraps and hides input textarea + var div = this.wrapper = hiddenTextarea(); + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var te = this.textarea = div.firstChild; + display.wrapper.insertBefore(div, display.wrapper.firstChild); + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) te.style.width = "0px"; + + on(te, "input", function() { + if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; + input.poll(); + }); + + on(te, "paste", function() { + // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 + // Add a char to the end of textarea before paste occur so that + // selection doesn't span to the end of textarea. + if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { + var start = te.selectionStart, end = te.selectionEnd; + te.value += "$"; + // The selection end needs to be set before the start, otherwise there + // can be an intermediate non-empty selection between the two, which + // can override the middle-click paste buffer on linux and cause the + // wrong thing to get pasted. + te.selectionEnd = end; + te.selectionStart = start; + cm.state.fakedLastChar = true; + } + cm.state.pasteIncoming = true; + input.fastPoll(); + }); + + function prepareCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (input.inaccurateSelection) { + input.prevInput = ""; + input.inaccurateSelection = false; + te.value = lastCopied.join("\n"); + selectInput(te); + } + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll); + } else { + input.prevInput = ""; + te.value = ranges.text.join("\n"); + selectInput(te); + } + } + if (e.type == "cut") cm.state.cutIncoming = true; + } + on(te, "cut", prepareCopyCut); + on(te, "copy", prepareCopyCut); + + on(display.scroller, "paste", function(e) { + if (eventInWidget(display, e)) return; + cm.state.pasteIncoming = true; + input.focus(); + }); + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function(e) { + if (!eventInWidget(display, e)) e_preventDefault(e); + }); + }, + + prepareSelection: function() { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc; + var result = prepareSelection(cm); + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + } + + return result; + }, + + showSelection: function(drawn) { + var cm = this.cm, display = cm.display; + removeChildrenAndAdd(display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px"; + this.wrapper.style.left = drawn.teLeft + "px"; + } + }, + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + reset: function(typing) { + if (this.contextMenuPending) return; + var minimal, selected, cm = this.cm, doc = cm.doc; + if (cm.somethingSelected()) { + this.prevInput = ""; + var range = doc.sel.primary(); + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + this.textarea.value = content; + if (cm.state.focused) selectInput(this.textarea); + if (ie && ie_version >= 9) this.hasSelection = content; + } else if (!typing) { + this.prevInput = this.textarea.value = ""; + if (ie && ie_version >= 9) this.hasSelection = null; + } + this.inaccurateSelection = minimal; + }, + + getField: function() { return this.textarea; }, + + supportsTouch: function() { return false; }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus(); } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } + }, + + blur: function() { this.textarea.blur(); }, + + resetPosition: function() { + this.wrapper.style.top = this.wrapper.style.left = 0; + }, + + receivedFocus: function() { this.slowPoll(); }, + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + slowPoll: function() { + var input = this; + if (input.pollingFast) return; + input.polling.set(this.cm.options.pollInterval, function() { + input.poll(); + if (input.cm.state.focused) input.slowPoll(); + }); + }, + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + fastPoll: function() { + var missed = false, input = this; + input.pollingFast = true; + function p() { + var changed = input.poll(); + if (!changed && !missed) {missed = true; input.polling.set(60, p);} + else {input.pollingFast = false; input.slowPoll();} + } + input.polling.set(20, p); + }, + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + poll: function() { + var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (!cm.state.focused || (hasSelection(input) && !prevInput) || + isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) + return false; + // See paste handler for more on the fakedLastChar kludge + if (cm.state.pasteIncoming && cm.state.fakedLastChar) { + input.value = input.value.substring(0, input.value.length - 1); + cm.state.fakedLastChar = false; + } + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) return false; + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset(); + return false; + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) prevInput = "\u200b"; + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + + var self = this; + runInOp(cm, function() { + applyTextInput(cm, text.slice(same), prevInput.length - same); + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; + else self.prevInput = text; + }); + return true; + }, + + ensurePolled: function() { + if (this.pollingFast && this.poll()) this.pollingFast = false; + }, + + onKeyPress: function() { + if (ie && ie_version >= 9) this.hasSelection = null; + this.fastPoll(); + }, + + onContextMenu: function(e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea; + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) return; // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + + var oldCSS = te.style.cssText; + input.wrapper.style.position = "absolute"; + te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) + display.input.focus(); + if (webkit) window.scrollTo(null, oldScrollY); + display.input.reset(); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) te.value = input.prevInput = " "; + input.contextMenuPending = true; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; + input.prevInput = selected ? "" : "\u200b"; + te.selectionStart = 1; te.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + input.contextMenuPending = false; + input.wrapper.style.position = "relative"; + te.style.cssText = oldCSS; + if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + var i = 0, poll = function() { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); + else display.input.reset(); + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) prepareSelectAllHack(); + if (captureRightClick) { + e_stop(e); + var mouseup = function() { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + }, + + setUneditable: nothing, + + needsContentAttribute: false + }, TextareaInput.prototype); + + // CONTENTEDITABLE INPUT STYLE + + function ContentEditableInput(cm) { + this.cm = cm; + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; + this.polling = new Delayed(); + this.gracePeriod = false; + } + + ContentEditableInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = input.cm; + var div = input.div = display.lineDiv; + div.contentEditable = "true"; + disableBrowserMagic(div); + + on(div, "paste", function(e) { + var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); + if (pasted) { + e.preventDefault(); + cm.replaceSelection(pasted, null, "paste"); + } + }); + + on(div, "compositionstart", function(e) { + var data = e.data; + input.composing = {sel: cm.doc.sel, data: data, startData: data}; + if (!data) return; + var prim = cm.doc.sel.primary(); + var line = cm.getLine(prim.head.line); + var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); + if (found > -1 && found <= prim.head.ch) + input.composing.sel = simpleSelection(Pos(prim.head.line, found), + Pos(prim.head.line, found + data.length)); + }); + on(div, "compositionupdate", function(e) { + input.composing.data = e.data; + }); + on(div, "compositionend", function(e) { + var ours = input.composing; + if (!ours) return; + if (e.data != ours.startData && !/\u200b/.test(e.data)) + ours.data = e.data; + // Need a small delay to prevent other code (input event, + // selection polling) from doing damage when fired right after + // compositionend. + setTimeout(function() { + if (!ours.handled) + input.applyComposition(ours); + if (input.composing == ours) + input.composing = null; + }, 50); + }); + + on(div, "touchstart", function() { + input.forceCompositionEnd(); + }); + + on(div, "input", function() { + if (input.composing) return; + if (!input.pollContent()) + runInOp(input.cm, function() {regChange(cm);}); + }); + + function onCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (e.type == "cut") cm.replaceSelection("", null, "cut"); + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.operation(function() { + cm.setSelections(ranges.ranges, 0, sel_dontScroll); + cm.replaceSelection("", null, "cut"); + }); + } + } + // iOS exposes the clipboard API, but seems to discard content inserted into it + if (e.clipboardData && !ios) { + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData("text/plain", lastCopied.join("\n")); + } else { + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild; + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); + te.value = lastCopied.join("\n"); + var hadFocus = document.activeElement; + selectInput(te); + setTimeout(function() { + cm.display.lineSpace.removeChild(kludge); + hadFocus.focus(); + }, 50); + } + } + on(div, "copy", onCopyCut); + on(div, "cut", onCopyCut); + }, + + prepareSelection: function() { + var result = prepareSelection(this.cm, false); + result.focus = this.cm.state.focused; + return result; + }, + + showSelection: function(info) { + if (!info || !this.cm.display.view.length) return; + if (info.focus) this.showPrimarySelection(); + this.showMultipleSelections(info); + }, + + showPrimarySelection: function() { + var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && + cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) + return; + + var start = posToDOM(this.cm, prim.from()); + var end = posToDOM(this.cm, prim.to()); + if (!start && !end) return; + + var view = this.cm.display.view; + var old = sel.rangeCount && sel.getRangeAt(0); + if (!start) { + start = {node: view[0].measure.map[2], offset: 0}; + } else if (!end) { // FIXME dangerously hacky + var measure = view[view.length - 1].measure; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; + } + + try { var rng = range(start.node, start.offset, end.offset, end.node); } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + sel.removeAllRanges(); + sel.addRange(rng); + if (old && sel.anchorNode == null) sel.addRange(old); + else if (gecko) this.startGracePeriod(); + } + this.rememberSelection(); + }, + + startGracePeriod: function() { + var input = this; + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function() { + input.gracePeriod = false; + if (input.selectionChanged()) + input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); + }, 20); + }, + + showMultipleSelections: function(info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + }, + + rememberSelection: function() { + var sel = window.getSelection(); + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + }, + + selectionInEditor: function() { + var sel = window.getSelection(); + if (!sel.rangeCount) return false; + var node = sel.getRangeAt(0).commonAncestorContainer; + return contains(this.div, node); + }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor") this.div.focus(); + }, + blur: function() { this.div.blur(); }, + getField: function() { return this.div; }, + + supportsTouch: function() { return true; }, + + receivedFocus: function() { + var input = this; + if (this.selectionInEditor()) + this.pollSelection(); + else + runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); + + function poll() { + if (input.cm.state.focused) { + input.pollSelection(); + input.polling.set(input.cm.options.pollInterval, poll); + } + } + this.polling.set(this.cm.options.pollInterval, poll); + }, + + selectionChanged: function() { + var sel = window.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + }, + + pollSelection: function() { + if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + var sel = window.getSelection(), cm = this.cm; + this.rememberSelection(); + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var head = domToPos(cm, sel.focusNode, sel.focusOffset); + if (anchor && head) runInOp(cm, function() { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); + if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; + }); + } + }, + + pollContent: function() { + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); + var from = sel.from(), to = sel.to(); + if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; + + var fromIndex; + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + var fromLine = lineNo(display.view[0].line); + var fromNode = display.view[0].node; + } else { + var fromLine = lineNo(display.view[fromIndex].line); + var fromNode = display.view[fromIndex - 1].node.nextSibling; + } + var toIndex = findViewIndex(cm, to.line); + if (toIndex == display.view.length - 1) { + var toLine = display.viewTo - 1; + var toNode = display.view[toIndex].node; + } else { + var toLine = lineNo(display.view[toIndex + 1].line) - 1; + var toNode = display.view[toIndex + 1].node.previousSibling; + } + + var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } + else break; + } + + var cutFront = 0, cutEnd = 0; + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + ++cutFront; + var newBot = lst(newText), oldBot = lst(oldText); + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)); + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + ++cutEnd; + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); + newText[0] = newText[0].slice(cutFront); + + var chFrom = Pos(fromLine, cutFront); + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input"); + return true; + } + }, + + ensurePolled: function() { + this.forceCompositionEnd(); + }, + reset: function() { + this.forceCompositionEnd(); + }, + forceCompositionEnd: function() { + if (!this.composing || this.composing.handled) return; + this.applyComposition(this.composing); + this.composing.handled = true; + this.div.blur(); + this.div.focus(); + }, + applyComposition: function(composing) { + if (composing.data && composing.data != composing.startData) + operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); + }, + + setUneditable: function(node) { + node.setAttribute("contenteditable", "false"); + }, + + onKeyPress: function(e) { + e.preventDefault(); + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + }, + + onContextMenu: nothing, + resetPosition: nothing, + + needsContentAttribute: true + }, ContentEditableInput.prototype); + + function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line); + if (!view || view.hidden) return null; + var line = getLine(cm.doc, pos.line); + var info = mapFromLineView(view, line, pos.line); + + var order = getOrder(line), side = "left"; + if (order) { + var partPos = getBidiPartAt(order, pos.ch); + side = partPos % 2 ? "right" : "left"; + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left"); + result.offset = result.collapse == "right" ? result.end : result.start; + return result; + } + + function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } + + function domToPos(cm, node, offset) { + var lineNode; + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset]; + if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); + node = null; offset = 0; + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) return null; + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i]; + if (lineView.node == lineNode) + return locateNodeInLineView(lineView, node, offset); + } + } + + function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false; + if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); + if (node == wrapper) { + bad = true; + node = wrapper.childNodes[offset]; + offset = 0; + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line; + return badPos(Pos(lineNo(line), line.text.length), bad); + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node; + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild; + if (offset) offset = textNode.nodeValue.length; + } + while (topNode.parentNode != wrapper) topNode = topNode.parentNode; + var measure = lineView.measure, maps = measure.maps; + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; + return Pos(line, ch); + } + } + } + } + var found = find(textNode, topNode, offset); + if (found) return badPos(found, bad); + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0); + if (found) + return badPos(Pos(found.line, found.ch - dist), bad); + else + dist += after.textContent.length; + } + for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1); + if (found) + return badPos(Pos(found.line, found.ch + dist), bad); + else + dist += after.textContent.length; + } + } + + function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false; + function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text"); + if (cmText != null) { + if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); + text += cmText; + return; + } + var markerID = node.getAttribute("cm-marker"), range; + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + if (found.length && (range = found[0].find())) + text += getBetween(cm.doc, range.from, range.to).join("\n"); + return; + } + if (node.getAttribute("contenteditable") == "false") return; + for (var i = 0; i < node.childNodes.length; i++) + walk(node.childNodes[i]); + if (/^(pre|div|p)$/i.test(node.nodeName)) + closing = true; + } else if (node.nodeType == 3) { + var val = node.nodeValue; + if (!val) return; + if (closing) { + text += "\n"; + closing = false; + } + text += val; + } + } + for (;;) { + walk(from); + if (from == to) break; + from = from.nextSibling; + } + return text; + } + + CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; + + // SELECTION / CURSOR + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + function Selection(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + } + + Selection.prototype = { + primary: function() { return this.ranges[this.primIndex]; }, + equals: function(other) { + if (other == this) return true; + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + for (var i = 0; i < this.ranges.length; i++) { + var here = this.ranges[i], there = other.ranges[i]; + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + } + return true; + }, + deepCopy: function() { + for (var out = [], i = 0; i < this.ranges.length; i++) + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); + return new Selection(out, this.primIndex); + }, + somethingSelected: function() { + for (var i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].empty()) return true; + return false; + }, + contains: function(pos, end) { + if (!end) end = pos; + for (var i = 0; i < this.ranges.length; i++) { + var range = this.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + return i; + } + return -1; + } + }; + + function Range(anchor, head) { + this.anchor = anchor; this.head = head; + } + + Range.prototype = { + from: function() { return minPos(this.anchor, this.head); }, + to: function() { return maxPos(this.anchor, this.head); }, + empty: function() { + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + } + }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex]; + ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) --primIndex; + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex); + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0); + } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} + function clipPosArray(doc, array) { + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); + return out; + } + + // SELECTION UPDATES + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head); + } else { + return new Range(other || head, head); + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); + var newSel = normalizeSelection(out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); + } + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); + else return sel; + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + sel = filterSelectionChange(doc, sel); + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + ensureCursorVisible(doc.cm); + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) return; + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) out = sel.ranges.slice(0, i); + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; + var dir = bias || 1; + doc.cantEdit = false; + search: for (;;) { + var line = getLine(doc, curPos.line); + if (line.markedSpans) { + for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; + var newPos = m.find(dir < 0 ? -1 : 1); + if (cmp(newPos, curPos) == 0) { + newPos.ch += dir; + if (newPos.ch < 0) { + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); + else newPos = null; + } else if (newPos.ch > line.text.length) { + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); + else newPos = null; + } + if (!newPos) { + if (flipped) { + // Driven in a corner -- no valid cursor position found at all + // -- try again *with* clearing, if we didn't already + if (!mayClear) return skipAtomic(doc, pos, bias, true); + // Otherwise, turn off editing until further notice, and return the start of the doc + doc.cantEdit = true; + return Pos(doc.first, 0); + } + flipped = true; newPos = pos; dir = -dir; + } + } + curPos = newPos; + continue search; + } + } + } + return curPos; + } + } + + // SELECTION DRAWING + + function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()); + } + + function prepareSelection(cm, primary) { + var doc = cm.doc, result = {}; + var curFragment = result.cursors = document.createDocumentFragment(); + var selFragment = result.selection = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (primary === false && i == doc.sel.primIndex) continue; + var range = doc.sel.ranges[i]; + var collapsed = range.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + drawSelectionCursor(cm, range, curFragment); + if (!collapsed) + drawSelectionRange(cm, range, selFragment); + } + return result; + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, range, output) { + var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + cursor.style.left = pos.left + "px"; + cursor.style.top = pos.top + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left + "px"; + otherCursor.style.top = pos.other.top + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } + } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left; + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + top = Math.round(top); + bottom = Math.round(bottom); + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + + "px; height: " + (bottom - top) + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = leftSide; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = leftSide; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = rightSide; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < leftSide + 1) left = leftSide; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return {start: start, end: end}; + } + + var sFrom = range.from(), sTo = range.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(leftSide, leftEnd.bottom, null, rightStart.top); + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function() { + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + else if (cm.options.cursorBlinkRate < 0) + display.cursorDiv.style.visibility = "hidden"; + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.viewTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + var changedLines = []; + + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles; + var highlighted = highlightLine(cm, line, state, true); + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) line.styleClasses = newCls; + else if (oldCls) line.styleClasses = null; + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) changedLines.push(doc.frontier); + line.stateAfter = copyState(doc.mode, state); + } else { + processLine(cm, line.text, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + if (changedLines.length) runInOp(cm, function() { + for (var i = 0; i < changedLines.length; i++) + regLineChange(cm, changedLines[i], "text"); + }); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function(line) { + processLine(cm, line.text, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + if (precise) doc.frontier = pos; + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop;} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; + return data; + } + + function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } + function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; + } + function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && displayWidth(cm); + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + heights.push((cur.bottom + next.top) / 2 - rect.top); + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + return {map: lineView.measure.map, cache: lineView.measure.cache}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest[i] == line) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineNo(lineView.rest[i]) > lineN) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view; + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + return cm.display.view[findViewIndex(cm, lineN)]; + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + return ext; + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) + view = null; + else if (view && view.changes) + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + if (!view) + view = updateExternalMeasurement(cm, line); + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + }; + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) ch = -1; + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + prepared.rect = prepared.view.text.getBoundingClientRect(); + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) prepared.cache[key] = found; + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom}; + } + + var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; + + function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + var mStart = map[i], mEnd = map[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) collapse = "right"; + } + if (start != null) { + node = map[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + collapse = bias; + if (bias == "left" && start == 0) + while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; + collapse = "left"; + } + if (bias == "right" && start == mEnd - mStart) + while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; + collapse = "right"; + } + break; + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; + } + + function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); + var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { + rect = node.parentNode.getBoundingClientRect(); + } else if (ie && cm.options.lineWrapping) { + var rects = range(node, start, end).getClientRects(); + if (rects.length) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = nullRect; + } else { + rect = range(node, start, end).getBoundingClientRect() || nullRect; + } + if (rect.left || rect.right || start == 0) break; + end = start; + start = start - 1; + collapse = "right"; + } + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) collapse = bias = "right"; + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = node.getBoundingClientRect(); + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; + else + rect = nullRect; + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + for (var i = 0; i < heights.length - 1; i++) + if (mid < heights[i]) break; + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot}; + if (!rect.left && !rect.right) result.bogus = true; + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + + return result; + } + + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + return rect; + var scaleX = screen.logicalXDPI / screen.deviceXDPI; + var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY}; + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + lineView.measure.caches[i] = {}; + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + clearLineMeasurementCacheFor(cm.display.view[i]); + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"/null (editor), "window", + // or "page". + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"/null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0, pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return {left: left, right: left, top: top, bottom: top + lineObj.height}; + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, outside, xRel) { + var pos = Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + var lineObj = getLine(doc, lineN); + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(0, true); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineN = lineNo(lineObj = mergedPos.to.line); + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (;;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var xDiff = x - (ch == from ? fromX : toX); + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, + xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + } + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var operationGroup = null; + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + }; + if (operationGroup) { + operationGroup.ops.push(cm.curOp); + } else { + cm.curOp.ownsGroup = operationGroup = { + ops: [cm.curOp], + delayedCallbacks: [] + }; + } + } + + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + callbacks[i](); + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); + } + } while (i < callbacks.length); + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp, group = op.ownsGroup; + if (!group) return; + + try { fireCallbacksForOps(group); } + finally { + operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + group.ops[i].cm.curOp = null; + endOperations(group); + } + } + + // The DOM updates done when an operation finishes are batched so + // that the minimum number of relayouts are required. + function endOperations(group) { + var ops = group.ops; + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R1(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W1(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R2(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W2(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_finish(ops[i]); + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; + maybeClipScrollbars(cm); + if (op.updateMaxLine) findMaxLine(cm); + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping; + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + } + + function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) updateHeightsInViewport(cm); + + op.barMeasure = measureForScrollbars(cm); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; + cm.display.sizerWidth = op.adjustWidthTo; + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + } + + if (op.updatedDisplay || op.selectionChanged) + op.preparedSelection = display.input.prepareSelection(); + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + if (op.maxScrollLeft < cm.doc.scrollLeft) + setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); + cm.display.maxLineChanged = false; + } + + if (op.preparedSelection) + cm.display.input.showSelection(op.preparedSelection); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); + if (op.updatedDisplay || op.startHeight != cm.doc.height) + updateScrollbars(cm, op.barMeasure); + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + cm.display.input.reset(op.typing); + if (op.focus && op.focus == activeElt()) ensureFocus(op.cm); + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; + + if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + display.wheelStartX = display.wheelStartY = null; + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); + display.scrollbars.setScrollTop(doc.scrollTop); + display.scroller.scrollTop = doc.scrollTop; + } + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); + display.scrollbars.setScrollLeft(doc.scrollLeft); + display.scroller.scrollLeft = doc.scrollLeft; + alignHorizontally(cm); + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + if (display.wrapper.offsetHeight) + doc.scrollTop = cm.display.scroller.scrollTop; + + // Fire change events, and delayed event handlers + if (op.changeObjs) + signal(cm, "changes", cm, op.changeObjs); + if (op.update) + op.update.finish(); + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) return f(); + startOperation(cm); + try { return f(); } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function() { + if (cm.curOp) return f.apply(cm, arguments); + startOperation(cm); + try { return f.apply(cm, arguments); } + finally { endOperation(cm); } + }; + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function() { + if (this.curOp) return f.apply(this, arguments); + startOperation(this); + try { return f.apply(this, arguments); } + finally { endOperation(this); } + }; + } + function docMethodOp(f) { + return function() { + var cm = this.cm; + if (!cm || cm.curOp) return f.apply(this, arguments); + startOperation(cm); + try { return f.apply(this, arguments); } + finally { endOperation(cm); } + }; + } + + // VIEW TRACKING + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array; + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + if (!lendiff) lendiff = 0; + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + display.updateLineNumbers = from; + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + resetView(cm); + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut = viewCuttingPoint(cm, from, from, -1); + if (cut) { + display.view = display.view.slice(0, cut.index); + display.viewTo = cut.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + ext.lineN += lendiff; + else if (from < ext.lineN + ext.size) + display.externalMeasured = null; + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + display.externalMeasured = null; + + if (line < display.viewFrom || line >= display.viewTo) return; + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) return; + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) arr.push(type); + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) return null; + n -= cm.display.viewFrom; + if (n < 0) return null; + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) return i; + } + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + return {index: index, lineN: newN}; + for (var i = 0, n = cm.display.viewFrom; i < index; i++) + n += view[i].size; + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) return null; + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) return null; + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return {index: index, lineN: newN}; + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + else if (display.viewFrom < from) + display.view = display.view.slice(findViewIndex(cm, from)); + display.viewFrom = from; + if (display.viewTo < to) + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + else if (display.viewTo > to) + display.view = display.view.slice(0, findViewIndex(cm, to)); + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + } + return dirty; + } + + // EVENT HANDLERS + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + on(d.scroller, "dblclick", operation(cm, function(e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = cm.findWordAt(pos); + extendSelection(cm.doc, word.anchor, word.head); + })); + else + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0}; + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); + prevTouch = d.activeTouch; + prevTouch.end = +new Date; + } + }; + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) return false; + var touch = e.touches[0]; + return touch.radiusX <= 1 && touch.radiusY <= 1; + } + function farAway(touch, other) { + if (other.left == null) return true; + var dx = other.left - touch.left, dy = other.top - touch.top; + return dx * dx + dy * dy > 20 * 20; + } + on(d.scroller, "touchstart", function(e) { + if (!isMouseLikeTouchEvent(e)) { + clearTimeout(touchFinished); + var now = +new Date; + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null}; + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX; + d.activeTouch.top = e.touches[0].pageY; + } + } + }); + on(d.scroller, "touchmove", function() { + if (d.activeTouch) d.activeTouch.moved = true; + }); + on(d.scroller, "touchend", function(e) { + var touch = d.activeTouch; + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range; + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + range = new Range(pos, pos); + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + range = cm.findWordAt(pos); + else // Triple tap + range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); + cm.setSelection(range.anchor, range.head); + cm.focus(); + e_preventDefault(e); + } + finishTouch(); + }); + on(d.scroller, "touchcancel", finishTouch); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function() { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + d.dragFunctions = { + simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, + start: function(e){onDragStart(cm, e);}, + drop: operation(cm, onDrop) + }; + + var inp = d.input.getField(); + on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); + on(inp, "keydown", operation(cm, onKeyDown)); + on(inp, "keypress", operation(cm, onKeyPress)); + on(inp, "focus", bind(onFocus, cm)); + on(inp, "blur", bind(onBlur, cm)); + } + + function dragDropChanged(cm, value, old) { + var wasOn = old && old != CodeMirror.Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.simple); + toggle(cm.display.scroller, "dragover", funcs.simple); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + + // Called when the window resizes + function onResize(cm) { + var d = cm.display; + if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) + return; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.scrollbarsClipped = false; + cm.setSize(); + } + + // MOUSE EVENTS + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + return true; + } + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; + + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null; } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords; + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + var cm = this, display = cm.display; + if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function(){display.scroller.draggable = true;}, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + window.focus(); + + switch (e_button(e)) { + case 1: + if (start) + leftButtonDown(cm, e, start); + else if (e_target(e) == display.scroller) + e_preventDefault(e); + break; + case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; + if (start) extendSelection(cm.doc, start); + setTimeout(function() {display.input.focus();}, 20); + e_preventDefault(e); + break; + case 3: + if (captureRightClick) onContextMenu(cm, e); + else delayBlurEvent(cm); + break; + } + } + + var lastClick, lastDoubleClick; + function leftButtonDown(cm, e, start) { + if (ie) setTimeout(bind(ensureFocus, cm), 0); + else cm.curOp.focus = activeElt(); + + var now = +new Date, type; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple"; + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + } else { + type = "single"; + lastClick = {time: now, pos: start}; + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && + type == "single" && (contained = sel.contains(start)) > -1 && + !sel.ranges[contained].empty()) + leftButtonStartDrag(cm, e, start, modifier); + else + leftButtonSelect(cm, e, start, type, modifier); + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display; + var dragEnd = operation(cm, function(e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + if (!modifier) + extendSelection(cm.doc, start); + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + setTimeout(function() {document.body.focus(); display.input.focus();}, 20); + else + display.input.focus(); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc; + e_preventDefault(e); + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + ourRange = ranges[ourIndex]; + else + ourRange = new Range(start, start); + } else { + ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; + } + + if (e.altKey) { + type = "rect"; + if (!addNew) ourRange = new Range(start, start); + start = posFromMouse(cm, e, true, true); + ourIndex = -1; + } else if (type == "double") { + var word = cm.findWordAt(start); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, word.anchor, word.head); + else + ourRange = word; + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, line.anchor, line.head); + else + ourRange = line; + } else { + ourRange = extendRange(doc, ourRange, start); + } + + if (!addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex == -1) { + ourIndex = ranges.length; + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); + startSel = doc.sel; + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) return; + lastPos = pos; + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + else if (text.length > leftPos) + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + } + if (!ranges.length) ranges.push(new Range(start, start)); + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var anchor = oldRange.anchor, head = pos; + if (type != "single") { + if (type == "double") + var range = cm.findWordAt(pos); + else + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); + } else { + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); + } + } + var ranges = startSel.ranges.slice(0); + ranges[ourIndex] = new Range(clipPos(doc, anchor), head); + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, type == "rect"); + if (!cur) return; + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt(); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function() { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + counter = Infinity; + e_preventDefault(e); + display.input.focus(); + off(document, "mousemove", move); + off(document, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function(e) { + if (!e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent, signalfn) { + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; + if (prevent) e_preventDefault(e); + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalfn(cm, type, cm, line, gutter, e); + return e_defaultPrevented(e); + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true, signalLater); + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || isReadOnly(cm)) return; + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function(file, i) { + var reader = new FileReader; + reader.onload = operation(cm, function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(cm.doc, pos); + var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + } + }); + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(function() {cm.display.input.focus();}, 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) + var selected = cm.listSelections(); + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) for (var i = 0; i < selected.length; ++i) + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); + cm.replaceSelection(text, "around", "paste"); + cm.display.input.focus(); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + e.dataTransfer.setData("Text", cm.getSelection()); + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) img.parentNode.removeChild(img); + } + } + + // SCROLL EVENTS + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplaySimple(cm, {top: val}); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + cm.display.scrollbars.setScrollTop(val); + if (gecko) updateDisplaySimple(cm); + startWorker(cm, 100); + } + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + cm.display.scrollbars.setScrollLeft(val); + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1/3; + + var wheelEventDelta = function(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + return {x: dx, y: dy}; + }; + CodeMirror.wheelEventPixels = function(e) { + var delta = wheelEventDelta(e); + delta.x *= wheelPixelsPerUnit; + delta.y *= wheelPixelsPerUnit; + return delta; + }; + + function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + if (!(dx && scroll.scrollWidth > scroll.clientWidth || + dy && scroll.scrollHeight > scroll.clientHeight)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer; + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplaySimple(cm, {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function() { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // KEY EVENTS + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled(); + var prevShift = cm.display.shift, done = false; + try { + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) cm.display.shift = false; + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); + if (result) return result; + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm); + } + + var stopSeq = new Delayed; + function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq; + if (seq) { + if (isModifierKey(name)) return "handled"; + stopSeq.set(50, function() { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null; + cm.display.input.reset(); + } + }); + name = seq + " " + name; + } + var result = lookupKeyForEditor(cm, name, handle); + + if (result == "multi") + cm.state.keySeq = name; + if (result == "handled") + signalLater(cm, "keyHandled", cm, name, e); + + if (result == "handled" || result == "multi") { + e_preventDefault(e); + restartBlink(cm); + } + + if (seq && !result && /\'$/.test(name)) { + e_preventDefault(e); + return true; + } + return !!result; + } + + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + var name = keyName(e, true); + if (!name) return false; + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) + || dispatchKey(cm, name, e, function(b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); + } + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, + function(b) { return doHandleBinding(cm, b, true); }); + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + cm.curOp.focus = activeElt(); + if (signalDOMEvent(cm, e)) return; + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection("", null, "cut"); + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + showCrossHair(cm); + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (e.keyCode == 16) this.doc.sel.shift = false; + signalDOMEvent(this, e); + } + + function onKeyPress(e) { + var cm = this; + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (handleCharBinding(cm, e, ch)) return; + cm.display.input.onKeyPress(e); + } + + // FOCUS/BLUR EVENTS + + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function() { + if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } + }, 100); + } + + function onFocus(cm) { + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset(); + if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 + } + cm.display.input.receivedFocus(); + } + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.delayingBlurEvent) return; + + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; + cm.display.input.onContextMenu(e); + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) return false; + return gutterEvent(cm, e, "gutterContextMenu", false, signal); + } + + // UPDATING + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + var changeEnd = CodeMirror.changeEnd = function(change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) return pos; + if (cmp(pos, change.to) <= 0) return changeEnd(change); + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; + return Pos(line, ch); + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(out, doc.sel.primIndex); + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + return Pos(nw.line, pos.ch - old.ch + nw.ch); + else + return Pos(nw.line + (pos.line - old.line), pos.ch); + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex); + } + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function() { this.canceled = true; } + }; + if (update) obj.update = function(from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits) return; + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + for (var i = 0; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + break; + } + if (i == source.length) return; + hist.lastOrigin = hist.lastSelOrigin = null; + + for (;;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}); + return; + } + selAfter = event; + } + else break; + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({changes: antiChanges, generation: hist.generation}); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return; + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) return; + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function(range) { + return new Range(Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch)); + }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + regLineChange(doc.cm, l, "gutter"); + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); + else updateDoc(doc, change, spans); + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function(line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + signalCursorActivity(cm); + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (change.full) + regChange(cm); + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + regLineChange(cm, from.line, "text"); + else + regChange(cm, from.line, to.line + 1, lendiff); + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) signalLater(cm, "change", cm, obj); + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}); + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, coords) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) return; + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + + coords.left + "px; width: 2px;"); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) margin = 0; + for (var limit = 0; limit < 5; limit++) { + var changed = false, coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + Math.min(coords.top, endCoords.top) - margin, + Math.max(coords.left, endCoords.left), + Math.max(coords.bottom, endCoords.bottom) + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) break; + } + return coords; + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = displayHeight(cm), result = {}; + if (y2 - y1 > screen) y2 = y1 + screen; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var tooWide = x2 - x1 > screenw; + if (tooWide) x2 = x1 + screenw; + if (x1 < 10) + result.scrollLeft = 0; + else if (x1 < screenleft) + result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); + else if (x2 > screenw + screenleft - 3) + result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; + return result; + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollPos(cm, left, top) { + if (left != null || top != null) resolveScrollToPos(cm); + if (left != null) + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + if (top != null) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(), from = cur, to = cur; + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; + to = Pos(cur.line, cur.ch + 1); + } + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos; + if (range) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + Math.min(from.top, to.top) - range.margin, + Math.max(from.right, to.right), + Math.max(from.bottom, to.bottom) + range.margin); + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + } + + // API UTILITIES + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) how = "add"; + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) how = "prev"; + else state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass || indentation > 150) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i, new Range(pos, pos)); + break; + } + } + } + line.stateAfter = null; + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); + return line; + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break; + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function() { + for (var i = kill.length - 1; i >= 0; i--) + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); + ensureCursorVisible(cm); + }); + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + var possible = true; + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return (possible = false); + } else ch = next; + return true; + } + + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) type = "s"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), origDir, true); + if (!possible) result.hitSide = true; + return result; + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (;;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + // EDITOR METHODS + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus();}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function(option) {return this.options[option];}, + getDoc: function() {return this.doc;}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function(spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: methodOp(function(how) { + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); + var start = Math.max(end, from.line); + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + indentLine(this, j, how); + var newRanges = this.doc.sel.ranges; + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise); + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true); + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) type = styles[2]; + else for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else { type = styles[mid * 2 + 2]; break; } + } + var cut = type ? type.indexOf("cm-overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0]; + }, + + getHelpers: function(pos, type) { + var found = []; + if (!helpers.hasOwnProperty(type)) return found; + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) found.push(help[mode[type]]); + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) found.push(val); + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i = 0; i < help._global.length; i++) { + var cur = help._global[i]; + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) + found.push(cur.val); + } + return found; + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary(); + if (start == null) pos = range.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? range.from() : range.to(); + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function(line, mode) { + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + + (end ? this.doc.height - heightAtLine(lineObj) : 0); + }, + + defaultTextHeight: function() { return textHeight(this.display); }, + defaultCharWidth: function() { return charWidth(this.display); }, + + setGutterMarker: methodOp(function(line, gutterID, value) { + return changeLine(this.doc, line, "gutter", function(line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: methodOp(function(gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regLineChange(cm, i, "gutter"); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + lineInfo: function(line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets}; + }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + node.setAttribute("cm-ignore-events", "true"); + this.display.input.setUneditable(node); + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + return commands[cmd](this); + }, + + findPosH: function(from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: methodOp(function(dir, unit) { + var cm = this; + cm.extendSelectionsBy(function(range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + else + return dir < 0 ? range.from() : range.to(); + }, sel_move); + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + doc.replaceSelection("", null, "+delete"); + else + deleteNearSelection(this, function(range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; + }); + }), + + findPosV: function(from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: methodOp(function(dir, unit) { + var cm = this, doc = this.doc, goals = []; + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function(range) { + if (collapse) + return dir < 0 ? range.from() : range.to(); + var headPos = cursorCoords(cm, range.head, "div"); + if (range.goalColumn != null) headPos.left = range.goalColumn; + goals.push(headPos.left); + var pos = findPosV(cm, headPos, dir, unit); + if (unit == "page" && range == doc.sel.primary()) + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); + return pos; + }, sel_move); + if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + doc.sel.ranges[i].goalColumn = goals[i]; + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = this.getHelper(pos, "wordChars"); + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function(ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + else + rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function() { return this.display.input.getField() == activeElt(); }, + + scrollTo: methodOp(function(x, y) { + if (x != null || y != null) resolveScrollToPos(this); + if (x != null) this.curOp.scrollLeft = x; + if (y != null) this.curOp.scrollTop = y; + }), + getScrollInfo: function() { + var scroller = this.display.scroller; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; + if (margin == null) margin = this.options.cursorScrollMargin; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; + } + if (!range.to) range.to = range.from; + range.margin = margin || 0; + + if (range.from.line != null) { + resolveScrollToPos(this); + this.curOp.scrollToPos = range; + } else { + var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + Math.min(range.from.top, range.to.top) - range.margin, + Math.max(range.from.right, range.to.right), + Math.max(range.from.bottom, range.to.bottom) + range.margin); + this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + }), + + setSize: methodOp(function(width, height) { + var cm = this; + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) cm.display.wrapper.style.width = interpret(width); + if (height != null) cm.display.wrapper.style.height = interpret(height); + if (cm.options.lineWrapping) clearLineMeasurementCache(this); + var lineNo = cm.display.viewFrom; + cm.doc.iter(lineNo, cm.display.viewTo, function(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } + ++lineNo; + }); + cm.curOp.forceUpdate = true; + signal(cm, "refresh", this); + }), + + operation: function(f){return runInOp(this, f);}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + this.display.input.reset(); + this.scrollTo(doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; + signalLater(this, "swapDoc", this, old); + return old; + }), + + getInputField: function(){return this.display.input.getField();}, + getWrapperElement: function(){return this.display.wrapper;}, + getScrollerElement: function(){return this.display.scroller;}, + getGutterElement: function(){return this.display.gutters;} + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + // Functions to run when options are changed. + var optionHandlers = CodeMirror.optionHandlers = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + } + + // Passed to option handlers when there is no old value. + var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function(cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != CodeMirror.Init) cm.refresh(); + }); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); + option("electricChars", true); + option("inputStyle", mobile ? "contenteditable" : "textarea", function() { + throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME + }, true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function(cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", function(cm, val, old) { + var next = getKeyMap(val); + var prev = old != CodeMirror.Init && getKeyMap(old); + if (prev && prev.detach) prev.detach(cm, next); + if (next.attach) next.attach(cm, prev || null); + }); + option("extraKeys", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function(cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); + option("scrollbarStyle", "native", function(cm) { + initScrollbars(cm); + updateScrollbars(cm); + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); + }, true); + option("lineNumbers", false, function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); + + option("readOnly", false, function(cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) cm.display.input.reset(); + } + }); + option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); + option("dragDrop", true, dragDropChanged); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.input.resetPosition(); + }); + + option("tabindex", null, function(cm, val) { + cm.display.input.getField().tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; + }; + + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") found = {name: found}; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; + }; + + // Minimal default mode. + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function(name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({pred: predicate, val: value}); + }; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because nested + // modes need to do this for their inner modes. + + var copyState = CodeMirror.copyState = function(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + }; + + var startState = CodeMirror.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + }; + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + CodeMirror.innerMode = function(mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; + }; + + // STANDARD COMMANDS + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, + singleSelection: function(cm) { + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + }, + killLine: function(cm) { + deleteNearSelection(cm, function(range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + return {from: range.head, to: Pos(range.head.line + 1, 0)}; + else + return {from: range.head, to: Pos(range.head.line, len)}; + } else { + return {from: range.from(), to: range.to()}; + } + }); + }, + deleteLine: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; + }); + }, + delLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), to: range.from()}; + }); + }, + delWrappedLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var leftPos = cm.coordsChar({left: 0, top: top}, "div"); + return {from: leftPos, to: range.from()}; + }); + }, + delWrappedLineRight: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + return {from: range.from(), to: rightPos }; + }); + }, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + undoSelection: function(cm) {cm.undoSelection();}, + redoSelection: function(cm) {cm.redoSelection();}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + goLineStart: function(cm) { + cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1}); + }, + goLineStartSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + return lineStartSmart(cm, range.head); + }, {origin: "+move", bias: 1}); + }, + goLineEnd: function(cm) { + cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1}); + }, + goLineRight: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + }, sel_move); + }, + goLineLeft: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: 0, top: top}, "div"); + }, sel_move); + }, + goLineLeftSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var pos = cm.coordsChar({left: 0, top: top}, "div"); + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); + return pos; + }, sel_move); + }, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goGroupRight: function(cm) {cm.moveH(1, "group");}, + goGroupLeft: function(cm) {cm.moveH(-1, "group");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharBefore: function(cm) {cm.deleteH(-1, "char");}, + delCharAfter: function(cm) {cm.deleteH(1, "char");}, + delWordBefore: function(cm) {cm.deleteH(-1, "word");}, + delWordAfter: function(cm) {cm.deleteH(1, "word");}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, + delGroupAfter: function(cm) {cm.deleteH(1, "group");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t");}, + insertSoftTab: function(cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); + } + cm.replaceSelections(spaces); + }, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.execCommand("insertTab"); + }, + transposeChars: function(cm) { + runInOp(cm, function() { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) + cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); + }, + newlineAndIndent: function(cm) { + runInOp(cm, function() { + var len = cm.listSelections().length; + for (var i = 0; i < len; i++) { + var range = cm.listSelections()[i]; + cm.replaceRange("\n", range.anchor, range.head, "+input"); + cm.indentLine(range.from().line + 1, null, true); + ensureCursorVisible(cm); + } + }); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; + var alt, ctrl, shift, cmd; + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; + else if (/^a(lt)?$/i.test(mod)) alt = true; + else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; + else if (/^s(hift)$/i.test(mod)) shift = true; + else throw new Error("Unrecognized modifier name: " + mod); + } + if (alt) name = "Alt-" + name; + if (ctrl) name = "Ctrl-" + name; + if (cmd) name = "Cmd-" + name; + if (shift) name = "Shift-" + name; + return name; + } + + // This is a kludge to keep keymaps mostly working as raw objects + // (backwards compatibility) while at the same time support features + // like normalization and multi-stroke key bindings. It compiles a + // new normalized keymap, and then updates the old object to reflect + // this. + CodeMirror.normalizeKeyMap = function(keymap) { + var copy = {}; + for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname]; + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; + if (value == "...") { delete keymap[keyname]; continue; } + + var keys = map(keyname.split(" "), normalizeKeyName); + for (var i = 0; i < keys.length; i++) { + var val, name; + if (i == keys.length - 1) { + name = keyname; + val = value; + } else { + name = keys.slice(0, i + 1).join(" "); + val = "..."; + } + var prev = copy[name]; + if (!prev) copy[name] = val; + else if (prev != val) throw new Error("Inconsistent bindings for " + name); + } + delete keymap[keyname]; + } + for (var prop in copy) keymap[prop] = copy[prop]; + return keymap; + }; + + var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + return lookupKey(key, map.fallthrough, handle, context); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); + if (result) return result; + } + } + }; + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + var isModifierKey = CodeMirror.isModifierKey = function(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + }; + + // Look up the name of a key as indicated by an event object. + var keyName = CodeMirror.keyName = function(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) return false; + var base = keyNames[event.keyCode], name = base; + if (name == null || event.altGraphKey) return false; + if (event.altKey && base != "Alt") name = "Alt-" + name; + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; + if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; + return name; + }; + + function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val; + } + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function(textarea, options) { + options = options ? copyObj(options) : {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabIndex) + options.tabindex = textarea.tabIndex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + options.finishInit = function(cm) { + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + }; + + textarea.style.display = "none"; + var cm = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + var nextMarkerId = 0; + + var TextMarker = CodeMirror.TextMarker = function(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + this.id = ++nextMarkerId; + }; + eventMixin(TextMarker); + + // Clear the marker. + TextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + else if (cm) { + if (span.to != null) max = lineNo(line); + if (span.from != null) min = lineNo(line); + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(this.lines[i]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm.doc); + } + if (cm) signalLater(cm, "markerCleared", cm, this); + if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function(side, lineObj) { + if (side == null && this.type == "bookmark") side = 1; + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) return from; + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) return to; + } + } + return from && {from: from, to: to}; + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function() { + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) return; + runInOp(cm, function() { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + updateLineHeight(line, line.height + dHeight); + } + }); + }; + + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function(line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) return markTextShared(doc, from, to, options, type); + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) copyObj(options, marker, false); + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + return marker; + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); + if (options.insertLeft) marker.widgetNode.insertLeft = true; + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + throw new Error("Inserting collapsed marker partially overlapping an existing one"); + sawCollapsedSpans = true; + } + + if (marker.addToHistory) + addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function(line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + updateMaxLine = true; + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.collapsed) + regChange(cm, from.line, to.line + 1); + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); + if (marker.atomic) reCheckSelection(cm.doc); + signalLater(cm, "markerAdded", cm, marker); + } + return marker; + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + markers[i].parent = this; + }; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function(side, lineObj) { + return this.primary.find(side, lineObj); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function(doc) { + if (widget) options.widgetNode = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function(m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } + return nw; + } + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } + return nw; + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + if (change.full) return null; + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + // Make sure we didn't create any zero-length spans + if (first) first = clearEmptySpans(first); + if (last && last != first) last = clearEmptySpans(last); + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + spans.splice(i--, 1); + } + if (!spans.length) return null; + return spans; + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function(line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + newParts.push({from: p.from, to: m.from}); + if (dto > 0 || !mk.inclusiveRight && !dto) + newParts.push({from: m.to, to: p.to}); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) return lenDiff; + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) return -fromCmp; + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) return toCmp; + return b.id - a.id; + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) continue; + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || + fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) + return true; + } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = merged.find(-1, true).line; + return line; + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + (lines || (lines = [])).push(line); + } + return lines; + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) return lineN; + return lineNo(vis); + } + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) return lineN; + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) return lineN; + while (merged = collapsedSpanAtEnd(line)) + line = merged.find(1, true).line; + return lineNo(line) + 1; + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.widgetNode) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + // LINE WIDGETS + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.doc = doc; + this.node = node; + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + addToScrollPos(cm, null, diff); + } + + LineWidget.prototype.clear = function() { + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) line.widgets = null; + var height = widgetHeight(this); + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) runInOp(cm, function() { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + }); + }; + LineWidget.prototype.changed = function() { + var oldH = this.height, cm = this.doc.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(line, line.height + diff); + if (cm) runInOp(cm, function() { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + }); + }; + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + var cm = widget.doc.cm; + if (!cm) return 0; + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; + if (widget.noHScroll) + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) cm.display.alignWidgets = true; + changeLine(doc, handle, "widget", function(line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, null, widget.height); + cm.curOp.forceUpdate = true; + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + Line.prototype.lineNo = function() { return lineNo(this); }; + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + function extractLineClasses(type, output) { + if (type) for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) break; + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + output[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + output[prop] += " " + lineClass[2]; + } + return type; + } + + function callBlankLine(mode, state) { + if (mode.blankLine) return mode.blankLine(state); + if (!mode.innerMode) return; + var inner = CodeMirror.innerMode(mode, state); + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + } + + function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; + var style = mode.token(stream, state); + if (stream.pos > stream.start) return style; + } + throw new Error("Mode " + mode.name + " failed to advance stream."); + } + + // Utility for getTokenAt and getLineTokens + function takeToken(cm, pos, precise, asArray) { + function getObj(copy) { + return {start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state}; + } + + var doc = cm.doc, mode = doc.mode, style; + pos = clipPos(doc, pos); + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); + var stream = new StringStream(line.text, cm.options.tabSize), tokens; + if (asArray) tokens = []; + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos; + style = readToken(mode, stream, state); + if (asArray) tokens.push(getObj(true)); + } + return asArray ? tokens : getObj(); + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + var inner = cm.options.addModeClass && [null]; + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); + } + if (inner) { + var mName = inner[0].name; + if (mName) style = "m-" + (style ? mName + " " + style : mName); + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 50000); + f(curStart, curStyle); + } + curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 characters + var pos = Math.min(stream.pos, curStart + 50000); + f(pos, curStyle); + curStart = pos; + } + } + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function(end, style) { + st.push(end, style); + }, lineClasses, forceToEnd); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function(end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i+1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, "cm-overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; + } + } + }, lineClasses); + } + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; + } + + function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + line.styles = result.styles; + if (result.classes) line.styleClasses = result.classes; + else if (line.styleClasses) line.styleClasses = null; + if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; + } + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "") callBlankLine(mode, state); + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + readToken(mode, stream, state); + stream.start = stream.pos; + } + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) return null; + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")); + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = {pre: elt("pre", [content]), content: content, + col: 0, pos: 0, cm: cm, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order; + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) + builder.addToken = buildTokenBadBidi(builder.addToken, order); + builder.map = []; + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + if (line.styleClasses.textClass) + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); + (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + // See issue #2901 + if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) + builder.content.className = "cm-tab-wrap-hack"; + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + + return builder; + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); + return token; + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) return; + var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; + var special = builder.cm.state.specialChars, mustWrap = false; + if (!special.test(text)) { + builder.col += text.length; + var content = document.createTextNode(displayText); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) mustWrap = true; + builder.pos += text.length; + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt.setAttribute("role", "presentation"); + txt.setAttribute("cm-text", "\t"); + builder.col += tabWidth; + } else { + var txt = builder.cm.options.specialCharPlaceholder(m[0]); + txt.setAttribute("cm-text", m[0]); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt); + builder.pos++; + } + } + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle, css); + if (title) token.title = title; + return builder.content.appendChild(token); + } + builder.content.appendChild(content); + } + + function splitSpaces(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function(builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (;;) { + // Find the part that overlaps with the start of this text + for (var i = 0; i < order.length; i++) { + var part = order[i]; + if (part.to > start && part.from <= start) break; + } + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) builder.map.push(builder.pos, builder.pos + size, widget); + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + widget = builder.content.appendChild(document.createElement("span")); + widget.setAttribute("cm-marker", marker.id); + } + if (widget) { + builder.cm.display.input.setUneditable(widget); + builder.content.appendChild(widget); + } + builder.pos += size; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i+=2) + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = ""; + collapsed = null; nextChange = Infinity; + var foundBookmarks = []; + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (sp.from <= pos && (sp.to == null || sp.to > pos)) { + if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } + if (m.className) spanStyle += " " + m.className; + if (m.css) css = m.css; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m); + } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return; + } + if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + function linesFor(start, end) { + for (var i = start, result = []; i < end; ++i) + result.push(new Line(text[i], spansFor(i), estimateHeight)); + return result; + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)); + doc.remove(text.length, doc.size - text.length); + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + var added = linesFor(1, text.length - 1); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + var added = linesFor(1, text.length - 1); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, height = 0; i < lines.length; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + // Remove the n lines at offset 'at'. + removeInner: function(at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + // Helper used to collapse a small branch into a single leaf. + collapse: function(lines) { + lines.push.apply(lines, this.lines); + }, + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + }, + // Used to iterate over a part of the tree. + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + removeInner: function(at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + }, + insertInner: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + // When a node has grown, check whether it should be split. + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function(at, n, op) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: splitLines(code), origin: "setValue", full: true}, true); + setSelection(this, simpleSelection(top)); + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(line); + }, + + lineCount: function() {return this.size;}, + firstLine: function() {return this.first;}, + lastLine: function() {return this.first + this.size - 1;}, + + clipPos: function(pos) {return clipPos(this, pos);}, + + getCursor: function(start) { + var range = this.sel.primary(), pos; + if (start == null || start == "head") pos = range.head; + else if (start == "anchor") pos = range.anchor; + else if (start == "end" || start == "to" || start === false) pos = range.to(); + else pos = range.from(); + return pos; + }, + listSelections: function() { return this.sel.ranges; }, + somethingSelected: function() {return this.sel.somethingSelected();}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads, options)); + }), + extendSelectionsBy: docMethodOp(function(f, options) { + extendSelections(this, map(this.sel.ranges, f), options); + }), + setSelections: docMethodOp(function(ranges, primary, options) { + if (!ranges.length) return; + for (var i = 0, out = []; i < ranges.length; i++) + out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); + setSelection(this, normalizeSelection(out, primary), options); + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + }), + + getSelection: function(lineSep) { + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) return lines; + else return lines.join(lineSep || "\n"); + }, + getSelections: function(lineSep) { + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) sel = sel.join(lineSep || "\n"); + parts[i] = sel; + } + return parts; + }, + replaceSelection: function(code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + dup[i] = code; + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i = changes.length - 1; i >= 0; i--) + makeChange(this, changes[i]); + if (newSel) setSelectionReplaceHistory(this, newSel); + else if (this.cm) ensureCursorVisible(this.cm); + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + + setExtending: function(val) {this.extend = val;}, + getExtending: function() {return this.extend;}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; + return {undo: done, redo: undone}; + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (classTest(cls).test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(classTest(cls)); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + removeLineWidget: function(widget) { widget.clear(); }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function(line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line|| + lineNo == to.line && span.from > to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function(options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy; + }, + unlinkDoc: function(other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode;}, + getEditor: function() {return this.cm;} + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments);}; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) findMaxLine(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + for (var chunk = doc; !chunk.lines;) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function(line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) for (var n = line; n; n = n.parent) n.height += diff; + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0; i < chunk.children.length; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = this.lastSelOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); + return histChange; + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) array.pop(); + else break; + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done); + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done); + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done); + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, ore are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + pushSelectionToHistory(doc.sel, hist.done); + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) hist.done.shift(); + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = hist.lastSelOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + hist.done[hist.done.length - 1] = sel; + else + pushSelectionToHistory(sel, hist.done); + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastSelOp = opId; + if (options && options.clearRedo !== false) + clearSelectionEvents(hist.undone); + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + dest.push(sel); + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue; + } + var changes = event.changes, newChanges = []; + copy.push({changes: newChanges}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue; + } + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT UTILITIES + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + var e_preventDefault = CodeMirror.e_preventDefault = function(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + }; + var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + }; + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var on = CodeMirror.on = function(emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + }; + + var off = CodeMirror.off = function(emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + for (var i = 0; i < arr.length; ++i) + if (arr[i] == f) { arr.splice(i, 1); break; } + } + }; + + var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + }; + + var orphanDelayedCallbacks = null; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + function signalLater(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); + } + function bnd(f) {return function(){f.apply(null, args);};}; + for (var i = 0; i < arr.length; ++i) + list.push(bnd(arr[i])); + } + + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) return; + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + set.push(arr[i]); + } + + function hasHandler(emitter, type) { + var arr = emitter._handlers && emitter._handlers[type]; + return arr && arr.length > 0; + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerGap = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + // Reused option objects for setSelection & friends + var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; + + function Delayed() {this.id = null;} + Delayed.prototype.set = function(ms, f) { + clearTimeout(this.id); + this.id = setTimeout(f, ms); + }; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + }; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) nextTab = string.length; + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + return pos + Math.min(skipped, goal - col); + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) return pos; + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length-1]; } + + var selectInput = function(node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + else if (ie) // Suppress mysterious IE10 errors + selectInput = function(node) { try { node.select(); } catch(_e) {} }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + if (array[i] == elt) return i; + return -1; + } + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); + return out; + } + + function nothing() {} + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + nothing.prototype = base; + inst = new nothing(); + } + if (props) copyObj(props, inst); + return inst; + }; + + function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args);}; + } + + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var isWordCharBasic = CodeMirror.isWordChar = function(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + }; + function isWordChar(ch, helper) { + if (!helper) return isWordCharBasic(ch); + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; + return helper.test(ch); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + var range; + if (document.createRange) range = function(node, start, end, endNode) { + var r = document.createRange(); + r.setEnd(endNode || node, end); + r.setStart(node, start); + return r; + }; + else range = function(node, start, end) { + var r = document.body.createTextRange(); + try { r.moveToElementText(node.parentNode); } + catch(e) { return r; } + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r; + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + var contains = CodeMirror.contains = function(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + child = child.parentNode; + if (parent.contains) + return parent.contains(child); + do { + if (child.nodeType == 11) child = child.host; + if (child == parent) return true; + } while (child = child.parentNode); + }; + + function activeElt() { return document.activeElement; } + // Older versions of IE throws unspecified error when touching + // document.activeElement in some cases (during loading, in iframe) + if (ie && ie_version < 11) activeElt = function() { + try { return document.activeElement; } + catch(e) { return document.body; } + }; + + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } + var rmClass = CodeMirror.rmClass = function(node, cls) { + var current = node.className; + var match = classTest(cls).exec(current); + if (match) { + var after = current.slice(match.index + match[0].length); + node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + } + }; + var addClass = CodeMirror.addClass = function(node, cls) { + var current = node.className; + if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; + }; + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; + return b; + } + + // WINDOW-WIDE EVENTS + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) return; + var byClass = document.body.getElementsByClassName("CodeMirror"); + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) f(cm); + } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) return; + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; + forEachCodeMirror(onResize); + }, 100); + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function() { + forEachCodeMirror(onBlur); + }); + } + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + node.setAttribute("cm-text", ""); + return node; + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) return badBidiRects; + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) + var r1 = range(txt, 1, 2).getBoundingClientRect(); + return badBidiRects = (r1.right - r0.right < 3); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function() { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function"; + })(); + + var badZoomedRects = null; + function hasBadZoomedRects(measure) { + if (badZoomedRects != null) return badZoomedRects; + var node = removeChildrenAndAdd(measure, elt("span", "x")); + var normal = node.getBoundingClientRect(); + var fromRange = range(node, 0, 1).getBoundingClientRect(); + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; + } + + // KEY NAMES + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line = getLine(cm.doc, lineN); + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + lineN = null; + } + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN == null ? lineNo(line) : lineN, ch); + } + function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line); + var line = getLine(cm.doc, start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; + return Pos(start.line, inWS ? 0 : firstNonWS); + } + return start; + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + bidiOther = null; + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) return i; + if ((cur.from == pos || cur.to == pos)) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + if (cur.from != cur.to) bidiOther = found; + return i; + } else { + if (cur.from != cur.to) bidiOther = i; + return found; + } + } + } + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar(line.text.charAt(pos))); + return pos; + } + + // This is needed in order to move 'visually' through bi-directional + // text -- i.e., pressing left should make the cursor go left, even + // when in RTL text. The tricky part is the 'jumps', where RTL and + // LTR text touch each other. This often requires the cursor offset + // to move more than one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + function charType(code) { + if (code <= 0xf7) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); + else if (0x6ee <= code && code <= 0x8ac) return "r"; + else if (0x2000 <= code && code <= 0x200b) return "w"; + else if (code == 0x200c) return "b"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function(str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i+1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + var before = (i ? types[i-1] : outerType) == "L"; + var after = (end < len ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} + order.push(new BidiSpan(0, start, i)); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) {} + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) {} + order.splice(at, 0, new BidiSpan(2, nstart, j)); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + if (order[0].level != lst(order).level) + order.push(new BidiSpan(order[0].level, len, len)); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "5.1.1"; + + return CodeMirror; +}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/policy-edit.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/policy-edit.js new file mode 100644 index 000000000..d42dd0109 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/policy-edit.js @@ -0,0 +1,729 @@ +/* + * 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. + */ + +var validateStep = {}; +var skipStep = {}; +var stepForwardFrom = {}; +var stepBackFrom = {}; +var policy = {}; +var configuredOperations = []; + +/** + * Method to update the visibility (i.e. disabled or enabled view) + * of grouped input according to the values + * that they currently possess. + * @param domElement HTML grouped-input element with class name "grouped-input" + */ +var updateGroupedInputVisibility = function (domElement) { + if ($(".parent-input:first", domElement).is(":checked")) { + if ($(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).removeClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', false); + }); + } else { + if (!$(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).addClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', true); + }); + } +}; + +skipStep["policy-platform"] = function (policyPayloadObj) { + policy["name"] = policyPayloadObj["policyName"]; + policy["platform"] = policyPayloadObj["profile"]["deviceType"]["name"]; + policy["platformId"] = policyPayloadObj["profile"]["deviceType"]["id"]; + var userRoleInput = $("#user-roles-input"); + var ownershipInput = $("#ownership-input"); + var userInput = $("#users-input"); + var actionInput = $("#action-input"); + var policyNameInput = $("#policy-name-input"); + var policyDescriptionInput = $("#policy-description-input"); + userRoleInput.val(policyPayloadObj.roles).trigger("change"); + userInput.val(policyPayloadObj.users).trigger("change"); + ownershipInput.val(policyPayloadObj.ownershipType); + actionInput.val(policyPayloadObj.compliance); + policyNameInput.val(policyPayloadObj["policyName"]); + policyDescriptionInput.val(policyPayloadObj["description"]); + // updating next-page wizard title with selected platform + $("#policy-profile-page-wizard-title").text("EDIT " + policy["platform"] + " POLICY - " + policy["name"]); + + var profileFeaturesList = policyPayloadObj["profile"]["profileFeaturesList"]; + if (profileFeaturesList.length > 0){ + var content = profileFeaturesList[0]["content"]; + var policyDefinitionObj = JSON.parse(content); + window.queryEditor.setValue(policyDefinitionObj["policyDefinition"]); + } +}; + +/** + * Checks if provided number is valid against a range. + * + * @param numberInput Number Input + * @param min Minimum Limit + * @param max Maximum Limit + * @returns {boolean} Returns true if input is within the specified range + */ +var inputIsValidAgainstRange = function (numberInput, min, max) { + return (numberInput == min || (numberInput > min && numberInput < max) || numberInput == max); +}; + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param input Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +var inputIsValidAgainstRegExp = function (regExp, input) { + return regExp.test(input); +}; + +validateStep["policy-profile"] = function () { + return true; +} + +stepForwardFrom["policy-profile"] = function () { + policy["profile"] = operationModule.generateProfile(policy["platform"], configuredOperations); + // updating next-page wizard title with selected platform + $("#policy-criteria-page-wizard-title").text("EDIT " + policy["platform"] + " POLICY - " + policy["name"]); +}; + +stepForwardFrom["policy-criteria"] = function () { + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(':radio')) { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + policy["selectedUsers"] = $("#users-input").val(); + } else if ($(this).attr("id") == "user-roles-radio-btn") { + policy["selectedUserRoles"] = $("#user-roles-input").val(); + } + } + } + }); + policy["selectedNonCompliantAction"] = $("#action-input").find(":selected").data("action"); + policy["selectedOwnership"] = $("#ownership-input").val(); + // updating next-page wizard title with selected platform + $("#policy-naming-page-wizard-title").text("EDIT " + policy["platform"] + " POLICY - " + policy["name"]); +}; + +/** + * Checks if provided input is valid against provided length range. + * + * @param input Alphanumeric or non-alphanumeric input + * @param minLength Minimum Required Length + * @param maxLength Maximum Required Length + * @returns {boolean} Returns true if input matches the provided minimum length and maximum length + */ +var inputIsValidAgainstLength = function (input, minLength, maxLength) { + var length = input.length; + return (length == minLength || (length > minLength && length < maxLength) || length == maxLength); +}; + +validateStep["policy-naming"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length. Please check."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-naming-publish"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length. Please check."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-naming-publish"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + updatePolicy(policy, "publish"); +}; +stepForwardFrom["policy-naming"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + updatePolicy(policy, "save"); +}; + +var updatePolicy = function (policy, state) { + var profilePayloads = [{ + "featureCode": "CONFIG", + "deviceTypeId": policy["platformId"], + "content": {"policyDefinition": window.queryEditor.getValue()} + }]; + + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": "ANY", + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"], + "name": policy["platform"] + }, + "profileFeaturesList": profilePayloads + } + }; + + if (policy["selectedUsers"]) { + payload["users"] = policy["selectedUsers"]; + } else if (policy["selectedUserRoles"]) { + payload["roles"] = policy["selectedUserRoles"]; + } else { + payload["users"] = []; + payload["roles"] = []; + } + + var serviceURL = "/devicemgt_admin/policies/" + getParameterByName("id"); + invokerUtil.put( + serviceURL, + payload, + // on success + function () { + if (state == "save"){ + var policyList = []; + policyList.push(getParameterByName("id")); + serviceURL = "/devicemgt_admin/policies/inactivate"; + invokerUtil.put( + serviceURL, + policyList, + // on success + function () { + $(".add-policy").addClass("hidden"); + $(".policy-message").removeClass("hidden"); + }, + // on error + function () { + + } + ); + }else if(state == "publish"){ + var policyList = []; + policyList.push(getParameterByName("id")); + serviceURL = "/devicemgt_admin/policies/activate"; + invokerUtil.put( + serviceURL, + policyList, + // on success + function () { + $(".add-policy").addClass("hidden"); + $(".policy-naming").addClass("hidden"); + $(".policy-message").removeClass("hidden"); + publishToDevice(); + }, + // on error + function () { + + } + ); + } + }, + // on error + function () { + + } + ); +}; + + +function publishToDevice() { + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": "ANY", + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"], + "name": policy["platform"] + }, + "policyDefinition": window.queryEditor.getValue(), + "policyDescription": policy["description"] + } + }; + + var successCallback = function (data, status) { + console.log("Data: " + data + "\nStatus: " + status); + }; + + var data = { + url: "/devicemgt/api/policies/add", + type: "POST", + contentType: "application/json", + accept: "application/json", + success: successCallback, + data: JSON.stringify(payload) + }; + + $.ajax(data).fail(function (jqXHR) { + console.log("Error: " + jqXHR); + }); + +} + +// Start of HTML embedded invoke methods +var showAdvanceOperation = function (operation, button) { + $(button).addClass('selected'); + $(button).siblings().removeClass('selected'); + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="' + operation + '"]').show(); + $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide(); +}; + +// Start of functions related to grid-input-view + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var setId = function (addFormContainer) { + $(addFormContainer).find("[data-add-form-clone]").each(function (i) { + $(this).attr("id", $(this).attr("data-add-form-clone").slice(1) + "-" + (i + 1)); + if ($(this).find(".index").length > 0) { + $(this).find(".index").html(i + 1); + } + }); +}; + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var showHideHelpText = function (addFormContainer) { + var helpText = "[data-help-text=add-form]"; + if ($(addFormContainer).find("[data-add-form-clone]").length > 0) { + $(addFormContainer).find(helpText).hide(); + } else { + $(addFormContainer).find(helpText).show(); + } +}; + +// End of functions related to grid-input-view + +/** + * This method will return query parameter value given its name. + * @param name Query parameter name + * @returns {string} Query parameter value + */ +var getParameterByName = function (name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); +}; + +function formatRepo (user) { + if (user.loading) { + return user.text + } + if (!user.username){ + return; + } + var markup = '
      ' + + '
      ' + + '
      ' + + '
      ' + user.username + '
      '; + if (user.firstname) { + markup += '
      ' + user.firstname + '
      '; + } + if (user.emailAddress) { + markup += '
      ' + user.emailAddress + '
      '; + } + markup += '
      '; + return markup; +} + +function formatRepoSelection (user) { + return user.username || user.text;; +} + +$(document).ready(function () { + + window.queryEditor = CodeMirror.fromTextArea(document.getElementById('policy-definition-input'), { + mode: MIME_TYPE_SIDDHI_QL, + indentWithTabs: true, + smartIndent: true, + lineNumbers: true, + matchBrackets: true, + autofocus: true, + extraKeys: { + "Shift-2": function (cm) { + insertStr(cm, cm.getCursor(), '@'); + CodeMirror.showHint(cm, getAnnotationHints); + }, + "Ctrl-Space": "autocomplete" + } + }); + + // Adding initial state of wizard-steps. + $("#policy-profile-wizard-steps").html($(".wr-steps").html()); + + $("select.select2[multiple=multiple]").select2({ + "tags": true + }); + + $("#users-input").select2({ + multiple:true, + tags: true, + ajax: { + url: window.location.origin + "/devicemgt/api/invoker/execute/", + method: "POST", + dataType: 'json', + delay: 250, + id: function (user) { + return user.username; + }, + data: function (params) { + var postData = {}; + postData.actionMethod = "GET"; + postData.actionUrl = "/devicemgt_admin/users?q=ad"; + postData.actionPayload = JSON.stringify({ + q: params.term, // search term + page: params.page + }); + + return JSON.stringify(postData); + }, + processResults: function (data, page) { + var newData = []; + $.each(data.responseContent, function (index, value) { + value.id = value.username; + newData.push(value); + }); + return { + results: newData + }; + }, + cache: true + }, + escapeMarkup: function (markup) { return markup; }, // let our custom formatter work + minimumInputLength: 1, + templateResult: formatRepo, // omitted for brevity, see the source of this page + templateSelection: formatRepoSelection // omitted for brevity, see the source of this page + }); + + var policyPayloadObj; + invokerUtil.get( + "/devicemgt_admin/policies/" + getParameterByName("id"), + // on success + function (data) { + data = JSON.parse(data); + policyPayloadObj = data["responseContent"]; + skipStep["policy-platform"](policyPayloadObj); + }, + // on error + function () { + // should be redirected to an error page + } + ); + + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + + $("input[type='radio'].select-users-radio").change(function () { + if ($("#users-radio-btn").is(":checked")) { + $("#user-roles-select-field").hide(); + $("#users-select-field").show(); + } + if ($("#user-roles-radio-btn").is(":checked")) { + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + } + }); + + // Support for special input type "ANY" on user(s) & user-role(s) selection + $("#user-roles-input").select2({ + "tags": true + }).on("select2:select", function (e) { + if (e.params.data.id == "ANY") { + $(this).val("ANY").trigger("change"); + } else { + $("option[value=ANY]", this).prop("selected", false).parent().trigger("change"); + } + }); + + // Maintains an array of configured features of the profile + var advanceOperations = ".wr-advance-operations"; + $(advanceOperations).on("click", ".wr-input-control.switch", function (event) { + var operationCode = $(this).parents(".operation-data").data("operation-code"); + var operation = $(this).parents(".operation-data").data("operation"); + var operationDataWrapper = $(this).data("target"); + // prevents event bubbling by figuring out what element it's being called from. + if (event.target.tagName == "INPUT") { + var featureConfiguredIcon; + if ($("input[type='checkbox']", this).is(":checked")) { + configuredOperations.push(operationCode); + // when a feature is enabled, if "zero-configured-features" msg is available, hide that. + var zeroConfiguredOperationsErrorMsg = "#policy-profile-main-error-msg"; + if (!$(zeroConfiguredOperationsErrorMsg).hasClass("hidden")) { + $(zeroConfiguredOperationsErrorMsg).addClass("hidden"); + } + // add configured-state-icon to the feature + featureConfiguredIcon = "#" + operation + "-configured"; + if ($(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).removeClass("hidden"); + } + } else { + //splicing the array if operation is present. + var index = $.inArray(operationCode, configuredOperations); + if (index != -1) { + configuredOperations.splice(index, 1); + } + // when a feature is disabled, clearing all its current configured, error or success states + var subErrorMsgWrapper = "#" + operation + "-feature-error-msg"; + var subErrorIcon = "#" + operation + "-error"; + var subOkIcon = "#" + operation + "-ok"; + featureConfiguredIcon = "#" + operation + "-configured"; + + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // reinitializing input fields into the defaults + $(operationDataWrapper + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(operationDataWrapper + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(operationDataWrapper + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(operationDataWrapper + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } + } + }); + + // adding support for cloning multiple profiles per feature with cloneable class definitions + $(advanceOperations).on("click", ".multi-view.add.enabled", function () { + // get a copy of .cloneable and create new .cloned div element + var cloned = "

      " + $(".cloneable", $(this).parent().parent()).html() + "
      "; + // append newly created .cloned div element to panel-body + $(this).parent().parent().append(cloned); + // enable remove action of newly cloned div element + $(".cloned", $(this).parent().parent()).each( + function () { + if ($(".multi-view.remove", this).hasClass("disabled")) { + $(".multi-view.remove", this).removeClass("disabled"); + } + if (!$(".multi-view.remove", this).hasClass("enabled")) { + $(".multi-view.remove", this).addClass("enabled"); + } + } + ); + }); + + $(advanceOperations).on("click", ".multi-view.remove.enabled", function () { + $(this).parent().remove(); + }); + + // enabling or disabling grouped-input based on the status of a parent check-box + $(advanceOperations).on("click", ".grouped-input", function () { + updateGroupedInputVisibility(this); + }); + + // add form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=add-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + var clonedForm = $("[data-add-form=" + $(this).attr("href") + "]").clone(). + find("[data-add-form-element=clone]").attr("data-add-form-clone", $(this).attr("href")); + + // adding class .child-input to capture text-input-array-values + $("input, select", clonedForm).addClass("child-input"); + + $(addFormContainer).append(clonedForm); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + // remove form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=remove-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + + $(this).closest("[data-add-form-element=clone]").remove(); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + $(".wizard-stepper").click(function () { + // button clicked here can be either a continue button or a back button. + var currentStep = $(this).data("current"); + var validationIsRequired = $(this).data("validate"); + var wizardIsToBeContinued; + + if (validationIsRequired) { + wizardIsToBeContinued = validateStep[currentStep](); + } else { + wizardIsToBeContinued = true; + } + + if (wizardIsToBeContinued) { + // When moving back and forth, following code segment will + // remove if there are any visible error-messages. + var errorMsgWrappers = ".alert.alert-danger"; + $(errorMsgWrappers).each( + function () { + if (!$(this).hasClass("hidden")) { + $(this).addClass("hidden"); + } + } + ); + + var nextStep = $(this).data("next"); + var isBackBtn = $(this).data("is-back-btn"); + + // if current button is a continuation... + if (!isBackBtn) { + // initiate stepForwardFrom[*] functions to gather form data. + if (stepForwardFrom[currentStep]) { + stepForwardFrom[currentStep](this); + } + } else { + // initiate stepBackFrom[*] functions to rollback. + if (stepBackFrom[currentStep]) { + stepBackFrom[currentStep](); + } + } + + // following step occurs only at the last stage of the wizard. + if (!nextStep) { + window.location.href = $(this).data("direct"); + } + + // updating next wizard step as current. + $(".itm-wiz").each(function () { + var step = $(this).data("step"); + if (step == nextStep) { + $(this).addClass("itm-wiz-current"); + } else { + $(this).removeClass("itm-wiz-current"); + } + }); + + // adding next update of wizard-steps. + $("#" + nextStep + "-wizard-steps").html($(".wr-steps").html()); + + // hiding current section of the wizard and showing next section. + $("." + currentStep).addClass("hidden"); + $("." + nextStep).removeClass("hidden"); + } + }); +}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/sql.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/sql.js new file mode 100644 index 000000000..9f92fbc93 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.edit/public/js/sql.js @@ -0,0 +1,310 @@ +/* + * 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. + */ + +/*Annotations, Annotation Names and relevant tokens*/ +var ANNOTATION_IMPORT = "Import"; +var ANNOTATION_EXPORT = "Export"; + +var ANNOTATION_TOKEN_AT = "@"; +var ANNOTATION_TOKEN_OPENING_BRACKET = "("; +var ANNOTATION_TOKEN_CLOSING_BRACKET = ")"; + +var REGEX_LINE_STARTING_WITH_PLAN = /^@Plan.*/g; +var REGEX_LINE_STARTING_WITH_SINGLE_LINE_COMMENT = /^--.*/g; +var REGEX_LINE_STARTING_WITH_MULTI_LINE_COMMENT = /^\/\*.*\*\//g; +var REGEX_LINE_STARTING_WITH_IMPORT_STATEMENT = /^@Import.*/g; + +var SIDDHI_STATEMENT_DELIMETER = ";"; +var SIDDHI_LINE_BREAK = "\n"; +var SIDDHI_LINE_BREAK_CHARACTER = '\n'; +var SIDDHI_SINGLE_QUOTE = "'"; +var SIDDHI_SPACE_LITERAL = " "; + +var SIDDHI_LITERAL_DEFINE_STREAM = "define stream"; + +var MIME_TYPE_SIDDHI_QL = "text/siddhi-ql"; + + +CodeMirror.defineMode("sql", function (config, parserConfig) { + "use strict"; + + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false":true, "true":true, "null":true}, + builtin = parserConfig.builtin || {}, + keywords = parserConfig.keywords || {}, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date":true, "time":true, "timestamp":true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + support.decimallessFloat == true && stream.eat('.'); + return "number"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if ((ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + return "number"; + } + } else { + stream.eatWhile(/^[_\-\w\d]/); /* Character '-' will also be eaten, to prevent the highlight happening in keywords being embedded in non-keyword strings. For example, 'all' in 'all-nonkeyword' */ + var word = stream.current().toLowerCase(); // Added toLowerCase() to highlight keywords in a case insensitive manner. + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function (stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev:state.context, + indent:stream.indentation(), + col:stream.column(), + type:type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState:function () { + return {tokenize:tokenBase, context:null}; + }, + + token:function (stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent:function (state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + var closing = textAfter.charAt(0) == cx.type; + if (cx.align) return cx.col + (closing ? 0 : 1); + else return cx.indent + (closing ? 0 : config.indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "--" + }; +}); + +(function () { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + } + + ; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywordsWithoutSymbols = "all and as begin by contains define delete end events " + + "every first for from full group having inner insert into join last " + + "left not of on or outer output partition raw return right select snapshot stream table "; + var sqlKeywords = ", : ? # ( ) " + sqlKeywordsWithoutSymbols; + var builtIn = "bool double float int long object string "; + var atoms = "false true null "; + var dateSQL = "days hours milliseconds minutes months seconds "; + var allSqlSuggestions = sqlKeywordsWithoutSymbols + builtIn + atoms + dateSQL; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME(MIME_TYPE_SIDDHI_QL, { + name:"sql", + keywords:set(sqlKeywords), + builtin:set(builtIn), + atoms:set(atoms), + operatorChars:/^[*+%<>!=/]/, + dateSQL:set(dateSQL), + support:set("doubleQuote "), + allSqlSuggestions:set(allSqlSuggestions) + }); +}()); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + functions: + A list of function names you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. + */ \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/css/codemirror.css b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/css/codemirror.css new file mode 100644 index 000000000..e749a5211 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/css/codemirror.css @@ -0,0 +1,342 @@ +/* + * 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. + */ + +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; + left: -30px; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +@-moz-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@-webkit-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +div.CodeMirror-overwrite div.CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + height: 100%; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; + left: -30px; +} +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + border-right: none; + width: 0; +} + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror ::selection { background: #d7d4f0; } +.CodeMirror ::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/codemirror.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/codemirror.js new file mode 100644 index 000000000..20f3f95ed --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/codemirror.js @@ -0,0 +1,8720 @@ +/* + * 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. + */ + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + module.exports = mod(); + else if (typeof define == "function" && define.amd) // AMD + return define([], mod); + else // Plain browser env + this.CodeMirror = mod(); +})(function() { + "use strict"; + + // BROWSER SNIFFING + + // Kludges for bugs and behavior differences that can't be feature + // detected are enabled based on userAgent etc sniffing. + + var gecko = /gecko\/\d/i.test(navigator.userAgent); + var ie_upto10 = /MSIE \d/.test(navigator.userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); + var ie = ie_upto10 || ie_11up; + var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); + var webkit = /WebKit\//.test(navigator.userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); + var chrome = /Chrome\//.test(navigator.userAgent); + var presto = /Opera\//.test(navigator.userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); + var phantom = /PhantomJS/.test(navigator.userAgent); + + var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + // This is woefully incomplete. Suggestions for alternative methods welcome. + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); + var mac = ios || /Mac/.test(navigator.platform); + var windows = /win/i.test(navigator.platform); + + var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); + if (presto_version) presto_version = Number(presto_version[1]); + if (presto_version && presto_version >= 15) { presto = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); + var captureRightClick = gecko || (ie && ie_version >= 9); + + // Optimize some code when these features are not used. + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + // EDITOR CONSTRUCTOR + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options ? copyObj(options) : {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + setGuttersForLineNumbers(options); + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(doc, options.mode); + this.doc = doc; + + var input = new CodeMirror.inputStyles[options.inputStyle](this); + var display = this.display = new Display(place, doc, input); + display.wrapper.CodeMirror = this; + updateGutters(this); + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + if (options.autofocus && !mobile) display.input.focus(); + initScrollbars(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + }; + + var cm = this; + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); + + registerEventHandlers(this); + ensureGlobalHandlers(); + + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); + + if ((options.autofocus && !mobile) || cm.hasFocus()) + setTimeout(bind(onFocus, this), 20); + else + onBlur(this); + + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](this, options[opt], Init); + maybeUpdateLineNumberWidth(this); + if (options.finishInit) options.finishInit(this); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + endOperation(this); + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + display.lineDiv.style.textRendering = "auto"; + } + + // DISPLAY CONSTRUCTOR + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc, input) { + var d = this; + this.input = input; + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.scrollbarFiller.setAttribute("cm-not-content", "true"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + d.gutterFiller.setAttribute("cm-not-content", "true"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = elt("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + d.sizerWidth = null; + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; + + if (place) { + if (place.appendChild) place.appendChild(d.wrapper); + else place(d.wrapper); + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + d.reportedViewFrom = d.reportedViewTo = doc.first; + // Information about the rendered lines. + d.view = []; + d.renderedView = null; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastWrapHeight = d.lastWrapWidth = 0; + d.updateLineNumbers = null; + + d.nativeBarWidth = d.barHeight = d.barWidth = 0; + d.scrollbarsClipped = false; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + + d.activeTouch = null; + + input.init(d); + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + cm.display.sizerWidth = null; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function(){updateScrollbars(cm);}, 100); + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function(line) { + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + else + return widgetsHeight + th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + updateGutterSpace(cm); + } + + function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth; + cm.display.sizer.style.marginLeft = width + "px"; + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(0, true); + len -= cur.text.length - found.from.ch; + cur = found.to.line; + len += cur.text.length - found.to.ch; + } + return len; + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(found, 1); + } + } + + // SCROLLBARS + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth; + var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + }; + } + + function NativeScrollbars(place, scroll, cm) { + this.cm = cm; + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + place(vert); place(horiz); + + on(vert, "scroll", function() { + if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); + }); + on(horiz, "scroll", function() { + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); + }); + + this.checkedOverlay = false; + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; + } + + NativeScrollbars.prototype = copyObj({ + update: function(measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + var sWidth = measure.nativeBarWidth; + + if (needsV) { + this.vert.style.display = "block"; + this.vert.style.bottom = needsH ? sWidth + "px" : "0"; + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + } else { + this.vert.style.display = ""; + this.vert.firstChild.style.height = "0"; + } + + if (needsH) { + this.horiz.style.display = "block"; + this.horiz.style.right = needsV ? sWidth + "px" : "0"; + this.horiz.style.left = measure.barLeft + "px"; + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.firstChild.style.width = + (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + } else { + this.horiz.style.display = ""; + this.horiz.firstChild.style.width = "0"; + } + + if (!this.checkedOverlay && measure.clientHeight > 0) { + if (sWidth == 0) this.overlayHack(); + this.checkedOverlay = true; + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; + }, + setScrollLeft: function(pos) { + if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; + }, + setScrollTop: function(pos) { + if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; + }, + overlayHack: function() { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + this.horiz.style.minHeight = this.vert.style.minWidth = w; + var self = this; + var barMouseDown = function(e) { + if (e_target(e) != self.vert && e_target(e) != self.horiz) + operation(self.cm, onMouseDown)(e); + }; + on(this.vert, "mousedown", barMouseDown); + on(this.horiz, "mousedown", barMouseDown); + }, + clear: function() { + var parent = this.horiz.parentNode; + parent.removeChild(this.horiz); + parent.removeChild(this.vert); + } + }, NativeScrollbars.prototype); + + function NullScrollbars() {} + + NullScrollbars.prototype = copyObj({ + update: function() { return {bottom: 0, right: 0}; }, + setScrollLeft: function() {}, + setScrollTop: function() {}, + clear: function() {} + }, NullScrollbars.prototype); + + CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; + + function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear(); + if (cm.display.scrollbars.addClass) + rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function() { + if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); + }); + node.setAttribute("cm-not-content", "true"); + }, function(pos, axis) { + if (axis == "horizontal") setScrollLeft(cm, pos); + else setScrollTop(cm, pos); + }, cm); + if (cm.display.scrollbars.addClass) + addClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + function updateScrollbars(cm, measure) { + if (!measure) measure = measureForScrollbars(cm); + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; + updateScrollbarsInner(cm, measure); + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + updateHeightsInViewport(cm); + updateScrollbarsInner(cm, measureForScrollbars(cm)); + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + } + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbarsInner(cm, measure) { + var d = cm.display; + var sizes = d.scrollbars.update(measure); + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = sizes.bottom + "px"; + d.scrollbarFiller.style.width = sizes.right + "px"; + } else d.scrollbarFiller.style.display = ""; + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sizes.bottom + "px"; + d.gutterFiller.style.width = measure.gutterWidth + "px"; + } else d.gutterFiller.style.display = ""; + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewport may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + if (ensureFrom < from) { + from = ensureFrom; + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); + to = ensureTo; + } + } + return {from: from, to: Math.max(to, from + 1)}; + } + + // LINE NUMBERS + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + if (cm.options.fixedGutter && view[i].gutter) + view[i].gutter.style.left = left; + var align = view[i].alignable; + if (align) for (var j = 0; j < align.length; j++) + align[j].style.left = left; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm); + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + } + + // DISPLAY DRAWING + + function DisplayUpdate(cm, viewport, force) { + var display = cm.display; + + this.viewport = viewport; + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport); + this.editorIsHidden = !display.wrapper.offsetWidth; + this.wrapperHeight = display.wrapper.clientHeight; + this.wrapperWidth = display.wrapper.clientWidth; + this.oldDisplayWidth = displayWidth(cm); + this.force = force; + this.dims = getDimensions(cm); + this.events = []; + } + + DisplayUpdate.prototype.signal = function(emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments); + }; + DisplayUpdate.prototype.finish = function() { + for (var i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]); + }; + + function maybeClipScrollbars(cm) { + var display = cm.display; + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; + display.heightForcer.style.height = scrollGap(cm) + "px"; + display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; + display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; + display.scrollbarsClipped = true; + } + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc; + + if (update.editorIsHidden) { + resetView(cm); + return false; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + return false; + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm); + update.dims = getDimensions(cm); + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, update.visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + return false; + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt(); + if (toUpdate > 4) display.lineDiv.style.display = "none"; + patchDisplay(cm, display.updateLineNumbers, update.dims); + if (toUpdate > 4) display.lineDiv.style.display = ""; + display.renderedView = display.view; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + display.gutters.style.height = 0; + + if (different) { + display.lastWrapHeight = update.wrapperHeight; + display.lastWrapWidth = update.wrapperWidth; + startWorker(cm, 400); + } + + display.updateLineNumbers = null; + + return true; + } + + function postUpdateDisplay(cm, update) { + var force = update.force, viewport = update.viewport; + for (var first = true;; first = false) { + if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) { + force = true; + } else { + force = false; + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + break; + } + if (!updateDisplayIfNeeded(cm, update)) break; + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + } + + update.signal(cm, "update", cm); + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + } + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm); + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + update.finish(); + } + } + + function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px"; + var total = measure.docHeight + cm.display.barHeight; + cm.display.heightForcer.style.top = total + "px"; + cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height; + if (cur.hidden) continue; + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + } + var diff = cur.line.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + updateWidgetHeight(cur.rest[j]); + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + line.widgets[i].height = line.widgets[i].node.offsetHeight; + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + var gutterLeft = d.gutters.clientLeft; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; + width[cm.options.gutters[i]] = n.clientWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth}; + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + node.style.display = "none"; + else + node.parentNode.removeChild(node); + return next; + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) cur = rm(cur); + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) cur = rm(cur); + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") updateLineText(cm, lineView); + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); + else if (type == "class") updateLineClasses(lineView); + else if (type == "widget") updateLineWidgets(cm, lineView, dims); + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + lineView.text.parentNode.replaceChild(lineView.node, lineView.text); + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + } + return lineView.node; + } + + function updateLineBackground(lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) cls += " CodeMirror-linebackground"; + if (lineView.background) { + if (cls) lineView.background.className = cls; + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built; + } + return buildLineContent(cm, lineView); + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) lineView.node = built.pre; + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(lineView) { + updateLineBackground(lineView); + if (lineView.line.wrapClass) + ensureLineWrapped(lineView).className = lineView.line.wrapClass; + else if (lineView.node != lineView.text) + lineView.node.className = ""; + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + + "px; width: " + dims.gutterTotalWidth + "px"); + cm.display.input.setUneditable(gutterWrap); + wrap.insertBefore(gutterWrap, lineView.text); + if (lineView.line.gutterClass) + gutterWrap.className += " " + lineView.line.gutterClass; + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + cm.display.lineNumInnerWidth + "px")); + if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + } + } + } + + function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) lineView.alignable = null; + for (var node = lineView.node.firstChild, next; node; node = next) { + var next = node.nextSibling; + if (node.className == "CodeMirror-linewidget") + lineView.node.removeChild(node); + } + insertLineWidgets(cm, lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) lineView.bgClass = built.bgClass; + if (built.textClass) lineView.textClass = built.textClass; + + updateLineClasses(lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(cm, lineView, dims); + return lineView.node; + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); + } + + function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) return; + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); + positionLineWidget(widget, node, lineView, dims); + cm.display.input.setUneditable(node); + if (allowAbove && widget.above) + wrap.insertBefore(node, lineView.gutter || lineView.text); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // POSITION OBJECT + + // A Pos instance represents a position within the text. + var Pos = CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; + + function copyPos(x) {return Pos(x.line, x.ch);} + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } + + // INPUT HANDLING + + function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + } + + function isReadOnly(cm) { + return cm.options.readOnly || cm.doc.cantEdit; + } + + // This will be set to an array of strings when copying, so that, + // when pasting, we know what kind of selections the copied text + // was made out of. + var lastCopied = null; + + function applyTextInput(cm, inserted, deleted, sel) { + var doc = cm.doc; + cm.display.shift = false; + if (!sel) sel = doc.sel; + + var textLines = splitLines(inserted), multiPaste = null; + // When pasing N lines into N selections, insert one line per selection + if (cm.state.pasteIncoming && sel.ranges.length > 1) { + if (lastCopied && lastCopied.join("\n") == inserted) + multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); + else if (textLines.length == sel.ranges.length) + multiPaste = map(textLines, function(l) { return [l]; }); + } + + // Normal behavior is to insert the new text into every selection + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + var from = range.from(), to = range.to(); + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + from = Pos(from.line, from.ch - deleted); + else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + } + var updateInput = cm.curOp.updateInput; + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, + origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + // When an 'electric' character is inserted, immediately trigger a reindent + if (inserted && !cm.state.pasteIncoming && cm.options.electricChars && + cm.options.smartIndent && range.head.ch < 100 && + (!i || sel.ranges[i - 1].head.line != range.head.line)) { + var mode = cm.getModeAt(range.head); + var end = changeEnd(changeEvent); + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indentLine(cm, end.line, "smart"); + break; + } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) + indentLine(cm, end.line, "smart"); + } + } + } + ensureCursorVisible(cm); + cm.curOp.updateInput = updateInput; + cm.curOp.typing = true; + cm.state.pasteIncoming = cm.state.cutIncoming = false; + } + + function copyableRanges(cm) { + var text = [], ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; + ranges.push(lineRange); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); + } + return {text: text, ranges: ranges}; + } + + function disableBrowserMagic(field) { + field.setAttribute("autocorrect", "off"); + field.setAttribute("autocapitalize", "off"); + field.setAttribute("spellcheck", "false"); + } + + // TEXTAREA INPUT STYLE + + function TextareaInput(cm) { + this.cm = cm; + // See input.poll and input.reset + this.prevInput = ""; + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false; + // Self-resetting timeout for the poller + this.polling = new Delayed(); + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false; + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false; + }; + + function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) te.style.width = "1000px"; + else te.setAttribute("wrap", "off"); + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) te.style.border = "1px solid black"; + disableBrowserMagic(te); + return div; + } + + TextareaInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = this.cm; + + // Wraps and hides input textarea + var div = this.wrapper = hiddenTextarea(); + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var te = this.textarea = div.firstChild; + display.wrapper.insertBefore(div, display.wrapper.firstChild); + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) te.style.width = "0px"; + + on(te, "input", function() { + if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; + input.poll(); + }); + + on(te, "paste", function() { + // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 + // Add a char to the end of textarea before paste occur so that + // selection doesn't span to the end of textarea. + if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { + var start = te.selectionStart, end = te.selectionEnd; + te.value += "$"; + // The selection end needs to be set before the start, otherwise there + // can be an intermediate non-empty selection between the two, which + // can override the middle-click paste buffer on linux and cause the + // wrong thing to get pasted. + te.selectionEnd = end; + te.selectionStart = start; + cm.state.fakedLastChar = true; + } + cm.state.pasteIncoming = true; + input.fastPoll(); + }); + + function prepareCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (input.inaccurateSelection) { + input.prevInput = ""; + input.inaccurateSelection = false; + te.value = lastCopied.join("\n"); + selectInput(te); + } + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll); + } else { + input.prevInput = ""; + te.value = ranges.text.join("\n"); + selectInput(te); + } + } + if (e.type == "cut") cm.state.cutIncoming = true; + } + on(te, "cut", prepareCopyCut); + on(te, "copy", prepareCopyCut); + + on(display.scroller, "paste", function(e) { + if (eventInWidget(display, e)) return; + cm.state.pasteIncoming = true; + input.focus(); + }); + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function(e) { + if (!eventInWidget(display, e)) e_preventDefault(e); + }); + }, + + prepareSelection: function() { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc; + var result = prepareSelection(cm); + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + } + + return result; + }, + + showSelection: function(drawn) { + var cm = this.cm, display = cm.display; + removeChildrenAndAdd(display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px"; + this.wrapper.style.left = drawn.teLeft + "px"; + } + }, + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + reset: function(typing) { + if (this.contextMenuPending) return; + var minimal, selected, cm = this.cm, doc = cm.doc; + if (cm.somethingSelected()) { + this.prevInput = ""; + var range = doc.sel.primary(); + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + this.textarea.value = content; + if (cm.state.focused) selectInput(this.textarea); + if (ie && ie_version >= 9) this.hasSelection = content; + } else if (!typing) { + this.prevInput = this.textarea.value = ""; + if (ie && ie_version >= 9) this.hasSelection = null; + } + this.inaccurateSelection = minimal; + }, + + getField: function() { return this.textarea; }, + + supportsTouch: function() { return false; }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus(); } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } + }, + + blur: function() { this.textarea.blur(); }, + + resetPosition: function() { + this.wrapper.style.top = this.wrapper.style.left = 0; + }, + + receivedFocus: function() { this.slowPoll(); }, + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + slowPoll: function() { + var input = this; + if (input.pollingFast) return; + input.polling.set(this.cm.options.pollInterval, function() { + input.poll(); + if (input.cm.state.focused) input.slowPoll(); + }); + }, + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + fastPoll: function() { + var missed = false, input = this; + input.pollingFast = true; + function p() { + var changed = input.poll(); + if (!changed && !missed) {missed = true; input.polling.set(60, p);} + else {input.pollingFast = false; input.slowPoll();} + } + input.polling.set(20, p); + }, + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + poll: function() { + var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (!cm.state.focused || (hasSelection(input) && !prevInput) || + isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) + return false; + // See paste handler for more on the fakedLastChar kludge + if (cm.state.pasteIncoming && cm.state.fakedLastChar) { + input.value = input.value.substring(0, input.value.length - 1); + cm.state.fakedLastChar = false; + } + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) return false; + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset(); + return false; + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) prevInput = "\u200b"; + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + + var self = this; + runInOp(cm, function() { + applyTextInput(cm, text.slice(same), prevInput.length - same); + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; + else self.prevInput = text; + }); + return true; + }, + + ensurePolled: function() { + if (this.pollingFast && this.poll()) this.pollingFast = false; + }, + + onKeyPress: function() { + if (ie && ie_version >= 9) this.hasSelection = null; + this.fastPoll(); + }, + + onContextMenu: function(e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea; + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) return; // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + + var oldCSS = te.style.cssText; + input.wrapper.style.position = "absolute"; + te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) + display.input.focus(); + if (webkit) window.scrollTo(null, oldScrollY); + display.input.reset(); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) te.value = input.prevInput = " "; + input.contextMenuPending = true; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; + input.prevInput = selected ? "" : "\u200b"; + te.selectionStart = 1; te.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + input.contextMenuPending = false; + input.wrapper.style.position = "relative"; + te.style.cssText = oldCSS; + if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + var i = 0, poll = function() { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); + else display.input.reset(); + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) prepareSelectAllHack(); + if (captureRightClick) { + e_stop(e); + var mouseup = function() { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + }, + + setUneditable: nothing, + + needsContentAttribute: false + }, TextareaInput.prototype); + + // CONTENTEDITABLE INPUT STYLE + + function ContentEditableInput(cm) { + this.cm = cm; + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; + this.polling = new Delayed(); + this.gracePeriod = false; + } + + ContentEditableInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = input.cm; + var div = input.div = display.lineDiv; + div.contentEditable = "true"; + disableBrowserMagic(div); + + on(div, "paste", function(e) { + var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); + if (pasted) { + e.preventDefault(); + cm.replaceSelection(pasted, null, "paste"); + } + }); + + on(div, "compositionstart", function(e) { + var data = e.data; + input.composing = {sel: cm.doc.sel, data: data, startData: data}; + if (!data) return; + var prim = cm.doc.sel.primary(); + var line = cm.getLine(prim.head.line); + var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); + if (found > -1 && found <= prim.head.ch) + input.composing.sel = simpleSelection(Pos(prim.head.line, found), + Pos(prim.head.line, found + data.length)); + }); + on(div, "compositionupdate", function(e) { + input.composing.data = e.data; + }); + on(div, "compositionend", function(e) { + var ours = input.composing; + if (!ours) return; + if (e.data != ours.startData && !/\u200b/.test(e.data)) + ours.data = e.data; + // Need a small delay to prevent other code (input event, + // selection polling) from doing damage when fired right after + // compositionend. + setTimeout(function() { + if (!ours.handled) + input.applyComposition(ours); + if (input.composing == ours) + input.composing = null; + }, 50); + }); + + on(div, "touchstart", function() { + input.forceCompositionEnd(); + }); + + on(div, "input", function() { + if (input.composing) return; + if (!input.pollContent()) + runInOp(input.cm, function() {regChange(cm);}); + }); + + function onCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (e.type == "cut") cm.replaceSelection("", null, "cut"); + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.operation(function() { + cm.setSelections(ranges.ranges, 0, sel_dontScroll); + cm.replaceSelection("", null, "cut"); + }); + } + } + // iOS exposes the clipboard API, but seems to discard content inserted into it + if (e.clipboardData && !ios) { + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData("text/plain", lastCopied.join("\n")); + } else { + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild; + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); + te.value = lastCopied.join("\n"); + var hadFocus = document.activeElement; + selectInput(te); + setTimeout(function() { + cm.display.lineSpace.removeChild(kludge); + hadFocus.focus(); + }, 50); + } + } + on(div, "copy", onCopyCut); + on(div, "cut", onCopyCut); + }, + + prepareSelection: function() { + var result = prepareSelection(this.cm, false); + result.focus = this.cm.state.focused; + return result; + }, + + showSelection: function(info) { + if (!info || !this.cm.display.view.length) return; + if (info.focus) this.showPrimarySelection(); + this.showMultipleSelections(info); + }, + + showPrimarySelection: function() { + var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && + cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) + return; + + var start = posToDOM(this.cm, prim.from()); + var end = posToDOM(this.cm, prim.to()); + if (!start && !end) return; + + var view = this.cm.display.view; + var old = sel.rangeCount && sel.getRangeAt(0); + if (!start) { + start = {node: view[0].measure.map[2], offset: 0}; + } else if (!end) { // FIXME dangerously hacky + var measure = view[view.length - 1].measure; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; + } + + try { var rng = range(start.node, start.offset, end.offset, end.node); } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + sel.removeAllRanges(); + sel.addRange(rng); + if (old && sel.anchorNode == null) sel.addRange(old); + else if (gecko) this.startGracePeriod(); + } + this.rememberSelection(); + }, + + startGracePeriod: function() { + var input = this; + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function() { + input.gracePeriod = false; + if (input.selectionChanged()) + input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); + }, 20); + }, + + showMultipleSelections: function(info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + }, + + rememberSelection: function() { + var sel = window.getSelection(); + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + }, + + selectionInEditor: function() { + var sel = window.getSelection(); + if (!sel.rangeCount) return false; + var node = sel.getRangeAt(0).commonAncestorContainer; + return contains(this.div, node); + }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor") this.div.focus(); + }, + blur: function() { this.div.blur(); }, + getField: function() { return this.div; }, + + supportsTouch: function() { return true; }, + + receivedFocus: function() { + var input = this; + if (this.selectionInEditor()) + this.pollSelection(); + else + runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); + + function poll() { + if (input.cm.state.focused) { + input.pollSelection(); + input.polling.set(input.cm.options.pollInterval, poll); + } + } + this.polling.set(this.cm.options.pollInterval, poll); + }, + + selectionChanged: function() { + var sel = window.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + }, + + pollSelection: function() { + if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + var sel = window.getSelection(), cm = this.cm; + this.rememberSelection(); + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var head = domToPos(cm, sel.focusNode, sel.focusOffset); + if (anchor && head) runInOp(cm, function() { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); + if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; + }); + } + }, + + pollContent: function() { + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); + var from = sel.from(), to = sel.to(); + if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; + + var fromIndex; + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + var fromLine = lineNo(display.view[0].line); + var fromNode = display.view[0].node; + } else { + var fromLine = lineNo(display.view[fromIndex].line); + var fromNode = display.view[fromIndex - 1].node.nextSibling; + } + var toIndex = findViewIndex(cm, to.line); + if (toIndex == display.view.length - 1) { + var toLine = display.viewTo - 1; + var toNode = display.view[toIndex].node; + } else { + var toLine = lineNo(display.view[toIndex + 1].line) - 1; + var toNode = display.view[toIndex + 1].node.previousSibling; + } + + var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } + else break; + } + + var cutFront = 0, cutEnd = 0; + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + ++cutFront; + var newBot = lst(newText), oldBot = lst(oldText); + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)); + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + ++cutEnd; + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); + newText[0] = newText[0].slice(cutFront); + + var chFrom = Pos(fromLine, cutFront); + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input"); + return true; + } + }, + + ensurePolled: function() { + this.forceCompositionEnd(); + }, + reset: function() { + this.forceCompositionEnd(); + }, + forceCompositionEnd: function() { + if (!this.composing || this.composing.handled) return; + this.applyComposition(this.composing); + this.composing.handled = true; + this.div.blur(); + this.div.focus(); + }, + applyComposition: function(composing) { + if (composing.data && composing.data != composing.startData) + operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); + }, + + setUneditable: function(node) { + node.setAttribute("contenteditable", "false"); + }, + + onKeyPress: function(e) { + e.preventDefault(); + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + }, + + onContextMenu: nothing, + resetPosition: nothing, + + needsContentAttribute: true + }, ContentEditableInput.prototype); + + function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line); + if (!view || view.hidden) return null; + var line = getLine(cm.doc, pos.line); + var info = mapFromLineView(view, line, pos.line); + + var order = getOrder(line), side = "left"; + if (order) { + var partPos = getBidiPartAt(order, pos.ch); + side = partPos % 2 ? "right" : "left"; + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left"); + result.offset = result.collapse == "right" ? result.end : result.start; + return result; + } + + function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } + + function domToPos(cm, node, offset) { + var lineNode; + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset]; + if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); + node = null; offset = 0; + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) return null; + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i]; + if (lineView.node == lineNode) + return locateNodeInLineView(lineView, node, offset); + } + } + + function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false; + if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); + if (node == wrapper) { + bad = true; + node = wrapper.childNodes[offset]; + offset = 0; + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line; + return badPos(Pos(lineNo(line), line.text.length), bad); + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node; + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild; + if (offset) offset = textNode.nodeValue.length; + } + while (topNode.parentNode != wrapper) topNode = topNode.parentNode; + var measure = lineView.measure, maps = measure.maps; + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; + return Pos(line, ch); + } + } + } + } + var found = find(textNode, topNode, offset); + if (found) return badPos(found, bad); + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0); + if (found) + return badPos(Pos(found.line, found.ch - dist), bad); + else + dist += after.textContent.length; + } + for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1); + if (found) + return badPos(Pos(found.line, found.ch + dist), bad); + else + dist += after.textContent.length; + } + } + + function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false; + function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text"); + if (cmText != null) { + if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); + text += cmText; + return; + } + var markerID = node.getAttribute("cm-marker"), range; + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + if (found.length && (range = found[0].find())) + text += getBetween(cm.doc, range.from, range.to).join("\n"); + return; + } + if (node.getAttribute("contenteditable") == "false") return; + for (var i = 0; i < node.childNodes.length; i++) + walk(node.childNodes[i]); + if (/^(pre|div|p)$/i.test(node.nodeName)) + closing = true; + } else if (node.nodeType == 3) { + var val = node.nodeValue; + if (!val) return; + if (closing) { + text += "\n"; + closing = false; + } + text += val; + } + } + for (;;) { + walk(from); + if (from == to) break; + from = from.nextSibling; + } + return text; + } + + CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; + + // SELECTION / CURSOR + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + function Selection(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + } + + Selection.prototype = { + primary: function() { return this.ranges[this.primIndex]; }, + equals: function(other) { + if (other == this) return true; + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + for (var i = 0; i < this.ranges.length; i++) { + var here = this.ranges[i], there = other.ranges[i]; + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + } + return true; + }, + deepCopy: function() { + for (var out = [], i = 0; i < this.ranges.length; i++) + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); + return new Selection(out, this.primIndex); + }, + somethingSelected: function() { + for (var i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].empty()) return true; + return false; + }, + contains: function(pos, end) { + if (!end) end = pos; + for (var i = 0; i < this.ranges.length; i++) { + var range = this.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + return i; + } + return -1; + } + }; + + function Range(anchor, head) { + this.anchor = anchor; this.head = head; + } + + Range.prototype = { + from: function() { return minPos(this.anchor, this.head); }, + to: function() { return maxPos(this.anchor, this.head); }, + empty: function() { + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + } + }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex]; + ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) --primIndex; + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex); + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0); + } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} + function clipPosArray(doc, array) { + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); + return out; + } + + // SELECTION UPDATES + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head); + } else { + return new Range(other || head, head); + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); + var newSel = normalizeSelection(out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); + } + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); + else return sel; + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + sel = filterSelectionChange(doc, sel); + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + ensureCursorVisible(doc.cm); + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) return; + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) out = sel.ranges.slice(0, i); + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; + var dir = bias || 1; + doc.cantEdit = false; + search: for (;;) { + var line = getLine(doc, curPos.line); + if (line.markedSpans) { + for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; + var newPos = m.find(dir < 0 ? -1 : 1); + if (cmp(newPos, curPos) == 0) { + newPos.ch += dir; + if (newPos.ch < 0) { + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); + else newPos = null; + } else if (newPos.ch > line.text.length) { + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); + else newPos = null; + } + if (!newPos) { + if (flipped) { + // Driven in a corner -- no valid cursor position found at all + // -- try again *with* clearing, if we didn't already + if (!mayClear) return skipAtomic(doc, pos, bias, true); + // Otherwise, turn off editing until further notice, and return the start of the doc + doc.cantEdit = true; + return Pos(doc.first, 0); + } + flipped = true; newPos = pos; dir = -dir; + } + } + curPos = newPos; + continue search; + } + } + } + return curPos; + } + } + + // SELECTION DRAWING + + function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()); + } + + function prepareSelection(cm, primary) { + var doc = cm.doc, result = {}; + var curFragment = result.cursors = document.createDocumentFragment(); + var selFragment = result.selection = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (primary === false && i == doc.sel.primIndex) continue; + var range = doc.sel.ranges[i]; + var collapsed = range.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + drawSelectionCursor(cm, range, curFragment); + if (!collapsed) + drawSelectionRange(cm, range, selFragment); + } + return result; + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, range, output) { + var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + cursor.style.left = pos.left + "px"; + cursor.style.top = pos.top + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left + "px"; + otherCursor.style.top = pos.other.top + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } + } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left; + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + top = Math.round(top); + bottom = Math.round(bottom); + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + + "px; height: " + (bottom - top) + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = leftSide; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = leftSide; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = rightSide; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < leftSide + 1) left = leftSide; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return {start: start, end: end}; + } + + var sFrom = range.from(), sTo = range.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(leftSide, leftEnd.bottom, null, rightStart.top); + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function() { + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + else if (cm.options.cursorBlinkRate < 0) + display.cursorDiv.style.visibility = "hidden"; + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.viewTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + var changedLines = []; + + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles; + var highlighted = highlightLine(cm, line, state, true); + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) line.styleClasses = newCls; + else if (oldCls) line.styleClasses = null; + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) changedLines.push(doc.frontier); + line.stateAfter = copyState(doc.mode, state); + } else { + processLine(cm, line.text, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + if (changedLines.length) runInOp(cm, function() { + for (var i = 0; i < changedLines.length; i++) + regLineChange(cm, changedLines[i], "text"); + }); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function(line) { + processLine(cm, line.text, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + if (precise) doc.frontier = pos; + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop;} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; + return data; + } + + function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } + function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; + } + function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && displayWidth(cm); + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + heights.push((cur.bottom + next.top) / 2 - rect.top); + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + return {map: lineView.measure.map, cache: lineView.measure.cache}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest[i] == line) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineNo(lineView.rest[i]) > lineN) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view; + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + return cm.display.view[findViewIndex(cm, lineN)]; + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + return ext; + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) + view = null; + else if (view && view.changes) + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + if (!view) + view = updateExternalMeasurement(cm, line); + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + }; + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) ch = -1; + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + prepared.rect = prepared.view.text.getBoundingClientRect(); + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) prepared.cache[key] = found; + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom}; + } + + var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; + + function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + var mStart = map[i], mEnd = map[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) collapse = "right"; + } + if (start != null) { + node = map[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + collapse = bias; + if (bias == "left" && start == 0) + while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; + collapse = "left"; + } + if (bias == "right" && start == mEnd - mStart) + while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; + collapse = "right"; + } + break; + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; + } + + function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); + var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { + rect = node.parentNode.getBoundingClientRect(); + } else if (ie && cm.options.lineWrapping) { + var rects = range(node, start, end).getClientRects(); + if (rects.length) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = nullRect; + } else { + rect = range(node, start, end).getBoundingClientRect() || nullRect; + } + if (rect.left || rect.right || start == 0) break; + end = start; + start = start - 1; + collapse = "right"; + } + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) collapse = bias = "right"; + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = node.getBoundingClientRect(); + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; + else + rect = nullRect; + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + for (var i = 0; i < heights.length - 1; i++) + if (mid < heights[i]) break; + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot}; + if (!rect.left && !rect.right) result.bogus = true; + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + + return result; + } + + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + return rect; + var scaleX = screen.logicalXDPI / screen.deviceXDPI; + var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY}; + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + lineView.measure.caches[i] = {}; + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + clearLineMeasurementCacheFor(cm.display.view[i]); + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"/null (editor), "window", + // or "page". + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"/null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0, pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return {left: left, right: left, top: top, bottom: top + lineObj.height}; + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, outside, xRel) { + var pos = Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + var lineObj = getLine(doc, lineN); + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(0, true); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineN = lineNo(lineObj = mergedPos.to.line); + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (;;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var xDiff = x - (ch == from ? fromX : toX); + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, + xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + } + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var operationGroup = null; + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + }; + if (operationGroup) { + operationGroup.ops.push(cm.curOp); + } else { + cm.curOp.ownsGroup = operationGroup = { + ops: [cm.curOp], + delayedCallbacks: [] + }; + } + } + + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + callbacks[i](); + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); + } + } while (i < callbacks.length); + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp, group = op.ownsGroup; + if (!group) return; + + try { fireCallbacksForOps(group); } + finally { + operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + group.ops[i].cm.curOp = null; + endOperations(group); + } + } + + // The DOM updates done when an operation finishes are batched so + // that the minimum number of relayouts are required. + function endOperations(group) { + var ops = group.ops; + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R1(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W1(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R2(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W2(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_finish(ops[i]); + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; + maybeClipScrollbars(cm); + if (op.updateMaxLine) findMaxLine(cm); + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping; + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + } + + function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) updateHeightsInViewport(cm); + + op.barMeasure = measureForScrollbars(cm); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; + cm.display.sizerWidth = op.adjustWidthTo; + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + } + + if (op.updatedDisplay || op.selectionChanged) + op.preparedSelection = display.input.prepareSelection(); + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + if (op.maxScrollLeft < cm.doc.scrollLeft) + setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); + cm.display.maxLineChanged = false; + } + + if (op.preparedSelection) + cm.display.input.showSelection(op.preparedSelection); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); + if (op.updatedDisplay || op.startHeight != cm.doc.height) + updateScrollbars(cm, op.barMeasure); + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + cm.display.input.reset(op.typing); + if (op.focus && op.focus == activeElt()) ensureFocus(op.cm); + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; + + if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + display.wheelStartX = display.wheelStartY = null; + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); + display.scrollbars.setScrollTop(doc.scrollTop); + display.scroller.scrollTop = doc.scrollTop; + } + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); + display.scrollbars.setScrollLeft(doc.scrollLeft); + display.scroller.scrollLeft = doc.scrollLeft; + alignHorizontally(cm); + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + if (display.wrapper.offsetHeight) + doc.scrollTop = cm.display.scroller.scrollTop; + + // Fire change events, and delayed event handlers + if (op.changeObjs) + signal(cm, "changes", cm, op.changeObjs); + if (op.update) + op.update.finish(); + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) return f(); + startOperation(cm); + try { return f(); } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function() { + if (cm.curOp) return f.apply(cm, arguments); + startOperation(cm); + try { return f.apply(cm, arguments); } + finally { endOperation(cm); } + }; + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function() { + if (this.curOp) return f.apply(this, arguments); + startOperation(this); + try { return f.apply(this, arguments); } + finally { endOperation(this); } + }; + } + function docMethodOp(f) { + return function() { + var cm = this.cm; + if (!cm || cm.curOp) return f.apply(this, arguments); + startOperation(cm); + try { return f.apply(this, arguments); } + finally { endOperation(cm); } + }; + } + + // VIEW TRACKING + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array; + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + if (!lendiff) lendiff = 0; + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + display.updateLineNumbers = from; + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + resetView(cm); + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut = viewCuttingPoint(cm, from, from, -1); + if (cut) { + display.view = display.view.slice(0, cut.index); + display.viewTo = cut.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + ext.lineN += lendiff; + else if (from < ext.lineN + ext.size) + display.externalMeasured = null; + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + display.externalMeasured = null; + + if (line < display.viewFrom || line >= display.viewTo) return; + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) return; + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) arr.push(type); + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) return null; + n -= cm.display.viewFrom; + if (n < 0) return null; + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) return i; + } + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + return {index: index, lineN: newN}; + for (var i = 0, n = cm.display.viewFrom; i < index; i++) + n += view[i].size; + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) return null; + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) return null; + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return {index: index, lineN: newN}; + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + else if (display.viewFrom < from) + display.view = display.view.slice(findViewIndex(cm, from)); + display.viewFrom = from; + if (display.viewTo < to) + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + else if (display.viewTo > to) + display.view = display.view.slice(0, findViewIndex(cm, to)); + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + } + return dirty; + } + + // EVENT HANDLERS + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + on(d.scroller, "dblclick", operation(cm, function(e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = cm.findWordAt(pos); + extendSelection(cm.doc, word.anchor, word.head); + })); + else + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0}; + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); + prevTouch = d.activeTouch; + prevTouch.end = +new Date; + } + }; + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) return false; + var touch = e.touches[0]; + return touch.radiusX <= 1 && touch.radiusY <= 1; + } + function farAway(touch, other) { + if (other.left == null) return true; + var dx = other.left - touch.left, dy = other.top - touch.top; + return dx * dx + dy * dy > 20 * 20; + } + on(d.scroller, "touchstart", function(e) { + if (!isMouseLikeTouchEvent(e)) { + clearTimeout(touchFinished); + var now = +new Date; + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null}; + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX; + d.activeTouch.top = e.touches[0].pageY; + } + } + }); + on(d.scroller, "touchmove", function() { + if (d.activeTouch) d.activeTouch.moved = true; + }); + on(d.scroller, "touchend", function(e) { + var touch = d.activeTouch; + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range; + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + range = new Range(pos, pos); + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + range = cm.findWordAt(pos); + else // Triple tap + range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); + cm.setSelection(range.anchor, range.head); + cm.focus(); + e_preventDefault(e); + } + finishTouch(); + }); + on(d.scroller, "touchcancel", finishTouch); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function() { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + d.dragFunctions = { + simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, + start: function(e){onDragStart(cm, e);}, + drop: operation(cm, onDrop) + }; + + var inp = d.input.getField(); + on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); + on(inp, "keydown", operation(cm, onKeyDown)); + on(inp, "keypress", operation(cm, onKeyPress)); + on(inp, "focus", bind(onFocus, cm)); + on(inp, "blur", bind(onBlur, cm)); + } + + function dragDropChanged(cm, value, old) { + var wasOn = old && old != CodeMirror.Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.simple); + toggle(cm.display.scroller, "dragover", funcs.simple); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + + // Called when the window resizes + function onResize(cm) { + var d = cm.display; + if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) + return; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.scrollbarsClipped = false; + cm.setSize(); + } + + // MOUSE EVENTS + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + return true; + } + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; + + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null; } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords; + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + var cm = this, display = cm.display; + if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function(){display.scroller.draggable = true;}, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + window.focus(); + + switch (e_button(e)) { + case 1: + if (start) + leftButtonDown(cm, e, start); + else if (e_target(e) == display.scroller) + e_preventDefault(e); + break; + case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; + if (start) extendSelection(cm.doc, start); + setTimeout(function() {display.input.focus();}, 20); + e_preventDefault(e); + break; + case 3: + if (captureRightClick) onContextMenu(cm, e); + else delayBlurEvent(cm); + break; + } + } + + var lastClick, lastDoubleClick; + function leftButtonDown(cm, e, start) { + if (ie) setTimeout(bind(ensureFocus, cm), 0); + else cm.curOp.focus = activeElt(); + + var now = +new Date, type; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple"; + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + } else { + type = "single"; + lastClick = {time: now, pos: start}; + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && + type == "single" && (contained = sel.contains(start)) > -1 && + !sel.ranges[contained].empty()) + leftButtonStartDrag(cm, e, start, modifier); + else + leftButtonSelect(cm, e, start, type, modifier); + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display; + var dragEnd = operation(cm, function(e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + if (!modifier) + extendSelection(cm.doc, start); + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + setTimeout(function() {document.body.focus(); display.input.focus();}, 20); + else + display.input.focus(); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc; + e_preventDefault(e); + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + ourRange = ranges[ourIndex]; + else + ourRange = new Range(start, start); + } else { + ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; + } + + if (e.altKey) { + type = "rect"; + if (!addNew) ourRange = new Range(start, start); + start = posFromMouse(cm, e, true, true); + ourIndex = -1; + } else if (type == "double") { + var word = cm.findWordAt(start); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, word.anchor, word.head); + else + ourRange = word; + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, line.anchor, line.head); + else + ourRange = line; + } else { + ourRange = extendRange(doc, ourRange, start); + } + + if (!addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex == -1) { + ourIndex = ranges.length; + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); + startSel = doc.sel; + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) return; + lastPos = pos; + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + else if (text.length > leftPos) + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + } + if (!ranges.length) ranges.push(new Range(start, start)); + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var anchor = oldRange.anchor, head = pos; + if (type != "single") { + if (type == "double") + var range = cm.findWordAt(pos); + else + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); + } else { + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); + } + } + var ranges = startSel.ranges.slice(0); + ranges[ourIndex] = new Range(clipPos(doc, anchor), head); + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, type == "rect"); + if (!cur) return; + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt(); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function() { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + counter = Infinity; + e_preventDefault(e); + display.input.focus(); + off(document, "mousemove", move); + off(document, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function(e) { + if (!e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent, signalfn) { + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; + if (prevent) e_preventDefault(e); + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalfn(cm, type, cm, line, gutter, e); + return e_defaultPrevented(e); + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true, signalLater); + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || isReadOnly(cm)) return; + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function(file, i) { + var reader = new FileReader; + reader.onload = operation(cm, function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(cm.doc, pos); + var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + } + }); + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(function() {cm.display.input.focus();}, 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) + var selected = cm.listSelections(); + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) for (var i = 0; i < selected.length; ++i) + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); + cm.replaceSelection(text, "around", "paste"); + cm.display.input.focus(); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + e.dataTransfer.setData("Text", cm.getSelection()); + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) img.parentNode.removeChild(img); + } + } + + // SCROLL EVENTS + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplaySimple(cm, {top: val}); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + cm.display.scrollbars.setScrollTop(val); + if (gecko) updateDisplaySimple(cm); + startWorker(cm, 100); + } + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + cm.display.scrollbars.setScrollLeft(val); + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1/3; + + var wheelEventDelta = function(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + return {x: dx, y: dy}; + }; + CodeMirror.wheelEventPixels = function(e) { + var delta = wheelEventDelta(e); + delta.x *= wheelPixelsPerUnit; + delta.y *= wheelPixelsPerUnit; + return delta; + }; + + function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + if (!(dx && scroll.scrollWidth > scroll.clientWidth || + dy && scroll.scrollHeight > scroll.clientHeight)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer; + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplaySimple(cm, {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function() { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // KEY EVENTS + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled(); + var prevShift = cm.display.shift, done = false; + try { + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) cm.display.shift = false; + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); + if (result) return result; + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm); + } + + var stopSeq = new Delayed; + function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq; + if (seq) { + if (isModifierKey(name)) return "handled"; + stopSeq.set(50, function() { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null; + cm.display.input.reset(); + } + }); + name = seq + " " + name; + } + var result = lookupKeyForEditor(cm, name, handle); + + if (result == "multi") + cm.state.keySeq = name; + if (result == "handled") + signalLater(cm, "keyHandled", cm, name, e); + + if (result == "handled" || result == "multi") { + e_preventDefault(e); + restartBlink(cm); + } + + if (seq && !result && /\'$/.test(name)) { + e_preventDefault(e); + return true; + } + return !!result; + } + + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + var name = keyName(e, true); + if (!name) return false; + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) + || dispatchKey(cm, name, e, function(b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); + } + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, + function(b) { return doHandleBinding(cm, b, true); }); + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + cm.curOp.focus = activeElt(); + if (signalDOMEvent(cm, e)) return; + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection("", null, "cut"); + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + showCrossHair(cm); + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (e.keyCode == 16) this.doc.sel.shift = false; + signalDOMEvent(this, e); + } + + function onKeyPress(e) { + var cm = this; + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (handleCharBinding(cm, e, ch)) return; + cm.display.input.onKeyPress(e); + } + + // FOCUS/BLUR EVENTS + + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function() { + if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } + }, 100); + } + + function onFocus(cm) { + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset(); + if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 + } + cm.display.input.receivedFocus(); + } + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.delayingBlurEvent) return; + + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; + cm.display.input.onContextMenu(e); + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) return false; + return gutterEvent(cm, e, "gutterContextMenu", false, signal); + } + + // UPDATING + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + var changeEnd = CodeMirror.changeEnd = function(change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) return pos; + if (cmp(pos, change.to) <= 0) return changeEnd(change); + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; + return Pos(line, ch); + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(out, doc.sel.primIndex); + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + return Pos(nw.line, pos.ch - old.ch + nw.ch); + else + return Pos(nw.line + (pos.line - old.line), pos.ch); + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex); + } + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function() { this.canceled = true; } + }; + if (update) obj.update = function(from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits) return; + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + for (var i = 0; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + break; + } + if (i == source.length) return; + hist.lastOrigin = hist.lastSelOrigin = null; + + for (;;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}); + return; + } + selAfter = event; + } + else break; + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({changes: antiChanges, generation: hist.generation}); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return; + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) return; + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function(range) { + return new Range(Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch)); + }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + regLineChange(doc.cm, l, "gutter"); + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); + else updateDoc(doc, change, spans); + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function(line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + signalCursorActivity(cm); + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (change.full) + regChange(cm); + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + regLineChange(cm, from.line, "text"); + else + regChange(cm, from.line, to.line + 1, lendiff); + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) signalLater(cm, "change", cm, obj); + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}); + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, coords) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) return; + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + + coords.left + "px; width: 2px;"); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) margin = 0; + for (var limit = 0; limit < 5; limit++) { + var changed = false, coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + Math.min(coords.top, endCoords.top) - margin, + Math.max(coords.left, endCoords.left), + Math.max(coords.bottom, endCoords.bottom) + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) break; + } + return coords; + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = displayHeight(cm), result = {}; + if (y2 - y1 > screen) y2 = y1 + screen; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var tooWide = x2 - x1 > screenw; + if (tooWide) x2 = x1 + screenw; + if (x1 < 10) + result.scrollLeft = 0; + else if (x1 < screenleft) + result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); + else if (x2 > screenw + screenleft - 3) + result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; + return result; + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollPos(cm, left, top) { + if (left != null || top != null) resolveScrollToPos(cm); + if (left != null) + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + if (top != null) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(), from = cur, to = cur; + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; + to = Pos(cur.line, cur.ch + 1); + } + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos; + if (range) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + Math.min(from.top, to.top) - range.margin, + Math.max(from.right, to.right), + Math.max(from.bottom, to.bottom) + range.margin); + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + } + + // API UTILITIES + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) how = "add"; + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) how = "prev"; + else state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass || indentation > 150) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i, new Range(pos, pos)); + break; + } + } + } + line.stateAfter = null; + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); + return line; + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break; + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function() { + for (var i = kill.length - 1; i >= 0; i--) + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); + ensureCursorVisible(cm); + }); + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + var possible = true; + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return (possible = false); + } else ch = next; + return true; + } + + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) type = "s"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), origDir, true); + if (!possible) result.hitSide = true; + return result; + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (;;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + // EDITOR METHODS + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus();}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function(option) {return this.options[option];}, + getDoc: function() {return this.doc;}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function(spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: methodOp(function(how) { + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); + var start = Math.max(end, from.line); + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + indentLine(this, j, how); + var newRanges = this.doc.sel.ranges; + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise); + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true); + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) type = styles[2]; + else for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else { type = styles[mid * 2 + 2]; break; } + } + var cut = type ? type.indexOf("cm-overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0]; + }, + + getHelpers: function(pos, type) { + var found = []; + if (!helpers.hasOwnProperty(type)) return found; + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) found.push(help[mode[type]]); + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) found.push(val); + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i = 0; i < help._global.length; i++) { + var cur = help._global[i]; + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) + found.push(cur.val); + } + return found; + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary(); + if (start == null) pos = range.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? range.from() : range.to(); + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function(line, mode) { + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + + (end ? this.doc.height - heightAtLine(lineObj) : 0); + }, + + defaultTextHeight: function() { return textHeight(this.display); }, + defaultCharWidth: function() { return charWidth(this.display); }, + + setGutterMarker: methodOp(function(line, gutterID, value) { + return changeLine(this.doc, line, "gutter", function(line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: methodOp(function(gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regLineChange(cm, i, "gutter"); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + lineInfo: function(line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets}; + }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + node.setAttribute("cm-ignore-events", "true"); + this.display.input.setUneditable(node); + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + return commands[cmd](this); + }, + + findPosH: function(from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: methodOp(function(dir, unit) { + var cm = this; + cm.extendSelectionsBy(function(range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + else + return dir < 0 ? range.from() : range.to(); + }, sel_move); + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + doc.replaceSelection("", null, "+delete"); + else + deleteNearSelection(this, function(range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; + }); + }), + + findPosV: function(from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: methodOp(function(dir, unit) { + var cm = this, doc = this.doc, goals = []; + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function(range) { + if (collapse) + return dir < 0 ? range.from() : range.to(); + var headPos = cursorCoords(cm, range.head, "div"); + if (range.goalColumn != null) headPos.left = range.goalColumn; + goals.push(headPos.left); + var pos = findPosV(cm, headPos, dir, unit); + if (unit == "page" && range == doc.sel.primary()) + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); + return pos; + }, sel_move); + if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + doc.sel.ranges[i].goalColumn = goals[i]; + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = this.getHelper(pos, "wordChars"); + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function(ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + else + rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function() { return this.display.input.getField() == activeElt(); }, + + scrollTo: methodOp(function(x, y) { + if (x != null || y != null) resolveScrollToPos(this); + if (x != null) this.curOp.scrollLeft = x; + if (y != null) this.curOp.scrollTop = y; + }), + getScrollInfo: function() { + var scroller = this.display.scroller; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; + if (margin == null) margin = this.options.cursorScrollMargin; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; + } + if (!range.to) range.to = range.from; + range.margin = margin || 0; + + if (range.from.line != null) { + resolveScrollToPos(this); + this.curOp.scrollToPos = range; + } else { + var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + Math.min(range.from.top, range.to.top) - range.margin, + Math.max(range.from.right, range.to.right), + Math.max(range.from.bottom, range.to.bottom) + range.margin); + this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + }), + + setSize: methodOp(function(width, height) { + var cm = this; + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) cm.display.wrapper.style.width = interpret(width); + if (height != null) cm.display.wrapper.style.height = interpret(height); + if (cm.options.lineWrapping) clearLineMeasurementCache(this); + var lineNo = cm.display.viewFrom; + cm.doc.iter(lineNo, cm.display.viewTo, function(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } + ++lineNo; + }); + cm.curOp.forceUpdate = true; + signal(cm, "refresh", this); + }), + + operation: function(f){return runInOp(this, f);}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + this.display.input.reset(); + this.scrollTo(doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; + signalLater(this, "swapDoc", this, old); + return old; + }), + + getInputField: function(){return this.display.input.getField();}, + getWrapperElement: function(){return this.display.wrapper;}, + getScrollerElement: function(){return this.display.scroller;}, + getGutterElement: function(){return this.display.gutters;} + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + // Functions to run when options are changed. + var optionHandlers = CodeMirror.optionHandlers = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + } + + // Passed to option handlers when there is no old value. + var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function(cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != CodeMirror.Init) cm.refresh(); + }); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); + option("electricChars", true); + option("inputStyle", mobile ? "contenteditable" : "textarea", function() { + throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME + }, true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function(cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", function(cm, val, old) { + var next = getKeyMap(val); + var prev = old != CodeMirror.Init && getKeyMap(old); + if (prev && prev.detach) prev.detach(cm, next); + if (next.attach) next.attach(cm, prev || null); + }); + option("extraKeys", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function(cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); + option("scrollbarStyle", "native", function(cm) { + initScrollbars(cm); + updateScrollbars(cm); + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); + }, true); + option("lineNumbers", false, function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); + + option("readOnly", false, function(cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) cm.display.input.reset(); + } + }); + option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); + option("dragDrop", true, dragDropChanged); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.input.resetPosition(); + }); + + option("tabindex", null, function(cm, val) { + cm.display.input.getField().tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; + }; + + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") found = {name: found}; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; + }; + + // Minimal default mode. + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function(name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({pred: predicate, val: value}); + }; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because nested + // modes need to do this for their inner modes. + + var copyState = CodeMirror.copyState = function(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + }; + + var startState = CodeMirror.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + }; + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + CodeMirror.innerMode = function(mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; + }; + + // STANDARD COMMANDS + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, + singleSelection: function(cm) { + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + }, + killLine: function(cm) { + deleteNearSelection(cm, function(range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + return {from: range.head, to: Pos(range.head.line + 1, 0)}; + else + return {from: range.head, to: Pos(range.head.line, len)}; + } else { + return {from: range.from(), to: range.to()}; + } + }); + }, + deleteLine: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; + }); + }, + delLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), to: range.from()}; + }); + }, + delWrappedLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var leftPos = cm.coordsChar({left: 0, top: top}, "div"); + return {from: leftPos, to: range.from()}; + }); + }, + delWrappedLineRight: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + return {from: range.from(), to: rightPos }; + }); + }, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + undoSelection: function(cm) {cm.undoSelection();}, + redoSelection: function(cm) {cm.redoSelection();}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + goLineStart: function(cm) { + cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1}); + }, + goLineStartSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + return lineStartSmart(cm, range.head); + }, {origin: "+move", bias: 1}); + }, + goLineEnd: function(cm) { + cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1}); + }, + goLineRight: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + }, sel_move); + }, + goLineLeft: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: 0, top: top}, "div"); + }, sel_move); + }, + goLineLeftSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var pos = cm.coordsChar({left: 0, top: top}, "div"); + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); + return pos; + }, sel_move); + }, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goGroupRight: function(cm) {cm.moveH(1, "group");}, + goGroupLeft: function(cm) {cm.moveH(-1, "group");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharBefore: function(cm) {cm.deleteH(-1, "char");}, + delCharAfter: function(cm) {cm.deleteH(1, "char");}, + delWordBefore: function(cm) {cm.deleteH(-1, "word");}, + delWordAfter: function(cm) {cm.deleteH(1, "word");}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, + delGroupAfter: function(cm) {cm.deleteH(1, "group");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t");}, + insertSoftTab: function(cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); + } + cm.replaceSelections(spaces); + }, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.execCommand("insertTab"); + }, + transposeChars: function(cm) { + runInOp(cm, function() { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) + cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); + }, + newlineAndIndent: function(cm) { + runInOp(cm, function() { + var len = cm.listSelections().length; + for (var i = 0; i < len; i++) { + var range = cm.listSelections()[i]; + cm.replaceRange("\n", range.anchor, range.head, "+input"); + cm.indentLine(range.from().line + 1, null, true); + ensureCursorVisible(cm); + } + }); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; + var alt, ctrl, shift, cmd; + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; + else if (/^a(lt)?$/i.test(mod)) alt = true; + else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; + else if (/^s(hift)$/i.test(mod)) shift = true; + else throw new Error("Unrecognized modifier name: " + mod); + } + if (alt) name = "Alt-" + name; + if (ctrl) name = "Ctrl-" + name; + if (cmd) name = "Cmd-" + name; + if (shift) name = "Shift-" + name; + return name; + } + + // This is a kludge to keep keymaps mostly working as raw objects + // (backwards compatibility) while at the same time support features + // like normalization and multi-stroke key bindings. It compiles a + // new normalized keymap, and then updates the old object to reflect + // this. + CodeMirror.normalizeKeyMap = function(keymap) { + var copy = {}; + for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname]; + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; + if (value == "...") { delete keymap[keyname]; continue; } + + var keys = map(keyname.split(" "), normalizeKeyName); + for (var i = 0; i < keys.length; i++) { + var val, name; + if (i == keys.length - 1) { + name = keyname; + val = value; + } else { + name = keys.slice(0, i + 1).join(" "); + val = "..."; + } + var prev = copy[name]; + if (!prev) copy[name] = val; + else if (prev != val) throw new Error("Inconsistent bindings for " + name); + } + delete keymap[keyname]; + } + for (var prop in copy) keymap[prop] = copy[prop]; + return keymap; + }; + + var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + return lookupKey(key, map.fallthrough, handle, context); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); + if (result) return result; + } + } + }; + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + var isModifierKey = CodeMirror.isModifierKey = function(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + }; + + // Look up the name of a key as indicated by an event object. + var keyName = CodeMirror.keyName = function(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) return false; + var base = keyNames[event.keyCode], name = base; + if (name == null || event.altGraphKey) return false; + if (event.altKey && base != "Alt") name = "Alt-" + name; + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; + if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; + return name; + }; + + function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val; + } + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function(textarea, options) { + options = options ? copyObj(options) : {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabIndex) + options.tabindex = textarea.tabIndex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + options.finishInit = function(cm) { + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + }; + + textarea.style.display = "none"; + var cm = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + var nextMarkerId = 0; + + var TextMarker = CodeMirror.TextMarker = function(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + this.id = ++nextMarkerId; + }; + eventMixin(TextMarker); + + // Clear the marker. + TextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + else if (cm) { + if (span.to != null) max = lineNo(line); + if (span.from != null) min = lineNo(line); + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(this.lines[i]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm.doc); + } + if (cm) signalLater(cm, "markerCleared", cm, this); + if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function(side, lineObj) { + if (side == null && this.type == "bookmark") side = 1; + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) return from; + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) return to; + } + } + return from && {from: from, to: to}; + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function() { + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) return; + runInOp(cm, function() { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + updateLineHeight(line, line.height + dHeight); + } + }); + }; + + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function(line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) return markTextShared(doc, from, to, options, type); + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) copyObj(options, marker, false); + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + return marker; + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); + if (options.insertLeft) marker.widgetNode.insertLeft = true; + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + throw new Error("Inserting collapsed marker partially overlapping an existing one"); + sawCollapsedSpans = true; + } + + if (marker.addToHistory) + addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function(line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + updateMaxLine = true; + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.collapsed) + regChange(cm, from.line, to.line + 1); + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); + if (marker.atomic) reCheckSelection(cm.doc); + signalLater(cm, "markerAdded", cm, marker); + } + return marker; + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + markers[i].parent = this; + }; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function(side, lineObj) { + return this.primary.find(side, lineObj); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function(doc) { + if (widget) options.widgetNode = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function(m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } + return nw; + } + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } + return nw; + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + if (change.full) return null; + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + // Make sure we didn't create any zero-length spans + if (first) first = clearEmptySpans(first); + if (last && last != first) last = clearEmptySpans(last); + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + spans.splice(i--, 1); + } + if (!spans.length) return null; + return spans; + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function(line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + newParts.push({from: p.from, to: m.from}); + if (dto > 0 || !mk.inclusiveRight && !dto) + newParts.push({from: m.to, to: p.to}); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) return lenDiff; + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) return -fromCmp; + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) return toCmp; + return b.id - a.id; + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) continue; + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || + fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) + return true; + } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = merged.find(-1, true).line; + return line; + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + (lines || (lines = [])).push(line); + } + return lines; + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) return lineN; + return lineNo(vis); + } + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) return lineN; + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) return lineN; + while (merged = collapsedSpanAtEnd(line)) + line = merged.find(1, true).line; + return lineNo(line) + 1; + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.widgetNode) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + // LINE WIDGETS + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.doc = doc; + this.node = node; + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + addToScrollPos(cm, null, diff); + } + + LineWidget.prototype.clear = function() { + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) line.widgets = null; + var height = widgetHeight(this); + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) runInOp(cm, function() { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + }); + }; + LineWidget.prototype.changed = function() { + var oldH = this.height, cm = this.doc.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(line, line.height + diff); + if (cm) runInOp(cm, function() { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + }); + }; + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + var cm = widget.doc.cm; + if (!cm) return 0; + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; + if (widget.noHScroll) + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) cm.display.alignWidgets = true; + changeLine(doc, handle, "widget", function(line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, null, widget.height); + cm.curOp.forceUpdate = true; + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + Line.prototype.lineNo = function() { return lineNo(this); }; + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + function extractLineClasses(type, output) { + if (type) for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) break; + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + output[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + output[prop] += " " + lineClass[2]; + } + return type; + } + + function callBlankLine(mode, state) { + if (mode.blankLine) return mode.blankLine(state); + if (!mode.innerMode) return; + var inner = CodeMirror.innerMode(mode, state); + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + } + + function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; + var style = mode.token(stream, state); + if (stream.pos > stream.start) return style; + } + throw new Error("Mode " + mode.name + " failed to advance stream."); + } + + // Utility for getTokenAt and getLineTokens + function takeToken(cm, pos, precise, asArray) { + function getObj(copy) { + return {start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state}; + } + + var doc = cm.doc, mode = doc.mode, style; + pos = clipPos(doc, pos); + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); + var stream = new StringStream(line.text, cm.options.tabSize), tokens; + if (asArray) tokens = []; + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos; + style = readToken(mode, stream, state); + if (asArray) tokens.push(getObj(true)); + } + return asArray ? tokens : getObj(); + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + var inner = cm.options.addModeClass && [null]; + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); + } + if (inner) { + var mName = inner[0].name; + if (mName) style = "m-" + (style ? mName + " " + style : mName); + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 50000); + f(curStart, curStyle); + } + curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 characters + var pos = Math.min(stream.pos, curStart + 50000); + f(pos, curStyle); + curStart = pos; + } + } + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function(end, style) { + st.push(end, style); + }, lineClasses, forceToEnd); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function(end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i+1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, "cm-overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; + } + } + }, lineClasses); + } + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; + } + + function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + line.styles = result.styles; + if (result.classes) line.styleClasses = result.classes; + else if (line.styleClasses) line.styleClasses = null; + if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; + } + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "") callBlankLine(mode, state); + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + readToken(mode, stream, state); + stream.start = stream.pos; + } + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) return null; + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")); + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = {pre: elt("pre", [content]), content: content, + col: 0, pos: 0, cm: cm, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order; + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) + builder.addToken = buildTokenBadBidi(builder.addToken, order); + builder.map = []; + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + if (line.styleClasses.textClass) + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); + (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + // See issue #2901 + if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) + builder.content.className = "cm-tab-wrap-hack"; + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + + return builder; + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); + return token; + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) return; + var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; + var special = builder.cm.state.specialChars, mustWrap = false; + if (!special.test(text)) { + builder.col += text.length; + var content = document.createTextNode(displayText); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) mustWrap = true; + builder.pos += text.length; + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt.setAttribute("role", "presentation"); + txt.setAttribute("cm-text", "\t"); + builder.col += tabWidth; + } else { + var txt = builder.cm.options.specialCharPlaceholder(m[0]); + txt.setAttribute("cm-text", m[0]); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt); + builder.pos++; + } + } + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle, css); + if (title) token.title = title; + return builder.content.appendChild(token); + } + builder.content.appendChild(content); + } + + function splitSpaces(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function(builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (;;) { + // Find the part that overlaps with the start of this text + for (var i = 0; i < order.length; i++) { + var part = order[i]; + if (part.to > start && part.from <= start) break; + } + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) builder.map.push(builder.pos, builder.pos + size, widget); + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + widget = builder.content.appendChild(document.createElement("span")); + widget.setAttribute("cm-marker", marker.id); + } + if (widget) { + builder.cm.display.input.setUneditable(widget); + builder.content.appendChild(widget); + } + builder.pos += size; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i+=2) + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = ""; + collapsed = null; nextChange = Infinity; + var foundBookmarks = []; + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (sp.from <= pos && (sp.to == null || sp.to > pos)) { + if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } + if (m.className) spanStyle += " " + m.className; + if (m.css) css = m.css; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m); + } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return; + } + if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + function linesFor(start, end) { + for (var i = start, result = []; i < end; ++i) + result.push(new Line(text[i], spansFor(i), estimateHeight)); + return result; + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)); + doc.remove(text.length, doc.size - text.length); + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + var added = linesFor(1, text.length - 1); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + var added = linesFor(1, text.length - 1); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, height = 0; i < lines.length; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + // Remove the n lines at offset 'at'. + removeInner: function(at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + // Helper used to collapse a small branch into a single leaf. + collapse: function(lines) { + lines.push.apply(lines, this.lines); + }, + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + }, + // Used to iterate over a part of the tree. + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + removeInner: function(at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + }, + insertInner: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + // When a node has grown, check whether it should be split. + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function(at, n, op) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: splitLines(code), origin: "setValue", full: true}, true); + setSelection(this, simpleSelection(top)); + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(line); + }, + + lineCount: function() {return this.size;}, + firstLine: function() {return this.first;}, + lastLine: function() {return this.first + this.size - 1;}, + + clipPos: function(pos) {return clipPos(this, pos);}, + + getCursor: function(start) { + var range = this.sel.primary(), pos; + if (start == null || start == "head") pos = range.head; + else if (start == "anchor") pos = range.anchor; + else if (start == "end" || start == "to" || start === false) pos = range.to(); + else pos = range.from(); + return pos; + }, + listSelections: function() { return this.sel.ranges; }, + somethingSelected: function() {return this.sel.somethingSelected();}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads, options)); + }), + extendSelectionsBy: docMethodOp(function(f, options) { + extendSelections(this, map(this.sel.ranges, f), options); + }), + setSelections: docMethodOp(function(ranges, primary, options) { + if (!ranges.length) return; + for (var i = 0, out = []; i < ranges.length; i++) + out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); + setSelection(this, normalizeSelection(out, primary), options); + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + }), + + getSelection: function(lineSep) { + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) return lines; + else return lines.join(lineSep || "\n"); + }, + getSelections: function(lineSep) { + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) sel = sel.join(lineSep || "\n"); + parts[i] = sel; + } + return parts; + }, + replaceSelection: function(code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + dup[i] = code; + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i = changes.length - 1; i >= 0; i--) + makeChange(this, changes[i]); + if (newSel) setSelectionReplaceHistory(this, newSel); + else if (this.cm) ensureCursorVisible(this.cm); + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + + setExtending: function(val) {this.extend = val;}, + getExtending: function() {return this.extend;}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; + return {undo: done, redo: undone}; + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (classTest(cls).test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(classTest(cls)); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + removeLineWidget: function(widget) { widget.clear(); }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function(line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line|| + lineNo == to.line && span.from > to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function(options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy; + }, + unlinkDoc: function(other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode;}, + getEditor: function() {return this.cm;} + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments);}; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) findMaxLine(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + for (var chunk = doc; !chunk.lines;) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function(line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) for (var n = line; n; n = n.parent) n.height += diff; + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0; i < chunk.children.length; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = this.lastSelOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); + return histChange; + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) array.pop(); + else break; + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done); + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done); + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done); + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, ore are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + pushSelectionToHistory(doc.sel, hist.done); + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) hist.done.shift(); + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = hist.lastSelOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + hist.done[hist.done.length - 1] = sel; + else + pushSelectionToHistory(sel, hist.done); + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastSelOp = opId; + if (options && options.clearRedo !== false) + clearSelectionEvents(hist.undone); + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + dest.push(sel); + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue; + } + var changes = event.changes, newChanges = []; + copy.push({changes: newChanges}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue; + } + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT UTILITIES + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + var e_preventDefault = CodeMirror.e_preventDefault = function(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + }; + var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + }; + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var on = CodeMirror.on = function(emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + }; + + var off = CodeMirror.off = function(emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + for (var i = 0; i < arr.length; ++i) + if (arr[i] == f) { arr.splice(i, 1); break; } + } + }; + + var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + }; + + var orphanDelayedCallbacks = null; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + function signalLater(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); + } + function bnd(f) {return function(){f.apply(null, args);};}; + for (var i = 0; i < arr.length; ++i) + list.push(bnd(arr[i])); + } + + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) return; + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + set.push(arr[i]); + } + + function hasHandler(emitter, type) { + var arr = emitter._handlers && emitter._handlers[type]; + return arr && arr.length > 0; + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerGap = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + // Reused option objects for setSelection & friends + var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; + + function Delayed() {this.id = null;} + Delayed.prototype.set = function(ms, f) { + clearTimeout(this.id); + this.id = setTimeout(f, ms); + }; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + }; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) nextTab = string.length; + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + return pos + Math.min(skipped, goal - col); + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) return pos; + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length-1]; } + + var selectInput = function(node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + else if (ie) // Suppress mysterious IE10 errors + selectInput = function(node) { try { node.select(); } catch(_e) {} }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + if (array[i] == elt) return i; + return -1; + } + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); + return out; + } + + function nothing() {} + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + nothing.prototype = base; + inst = new nothing(); + } + if (props) copyObj(props, inst); + return inst; + }; + + function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args);}; + } + + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var isWordCharBasic = CodeMirror.isWordChar = function(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + }; + function isWordChar(ch, helper) { + if (!helper) return isWordCharBasic(ch); + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; + return helper.test(ch); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + var range; + if (document.createRange) range = function(node, start, end, endNode) { + var r = document.createRange(); + r.setEnd(endNode || node, end); + r.setStart(node, start); + return r; + }; + else range = function(node, start, end) { + var r = document.body.createTextRange(); + try { r.moveToElementText(node.parentNode); } + catch(e) { return r; } + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r; + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + var contains = CodeMirror.contains = function(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + child = child.parentNode; + if (parent.contains) + return parent.contains(child); + do { + if (child.nodeType == 11) child = child.host; + if (child == parent) return true; + } while (child = child.parentNode); + }; + + function activeElt() { return document.activeElement; } + // Older versions of IE throws unspecified error when touching + // document.activeElement in some cases (during loading, in iframe) + if (ie && ie_version < 11) activeElt = function() { + try { return document.activeElement; } + catch(e) { return document.body; } + }; + + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } + var rmClass = CodeMirror.rmClass = function(node, cls) { + var current = node.className; + var match = classTest(cls).exec(current); + if (match) { + var after = current.slice(match.index + match[0].length); + node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + } + }; + var addClass = CodeMirror.addClass = function(node, cls) { + var current = node.className; + if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; + }; + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; + return b; + } + + // WINDOW-WIDE EVENTS + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) return; + var byClass = document.body.getElementsByClassName("CodeMirror"); + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) f(cm); + } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) return; + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; + forEachCodeMirror(onResize); + }, 100); + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function() { + forEachCodeMirror(onBlur); + }); + } + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + node.setAttribute("cm-text", ""); + return node; + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) return badBidiRects; + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) + var r1 = range(txt, 1, 2).getBoundingClientRect(); + return badBidiRects = (r1.right - r0.right < 3); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function() { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function"; + })(); + + var badZoomedRects = null; + function hasBadZoomedRects(measure) { + if (badZoomedRects != null) return badZoomedRects; + var node = removeChildrenAndAdd(measure, elt("span", "x")); + var normal = node.getBoundingClientRect(); + var fromRange = range(node, 0, 1).getBoundingClientRect(); + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; + } + + // KEY NAMES + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line = getLine(cm.doc, lineN); + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + lineN = null; + } + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN == null ? lineNo(line) : lineN, ch); + } + function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line); + var line = getLine(cm.doc, start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; + return Pos(start.line, inWS ? 0 : firstNonWS); + } + return start; + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + bidiOther = null; + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) return i; + if ((cur.from == pos || cur.to == pos)) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + if (cur.from != cur.to) bidiOther = found; + return i; + } else { + if (cur.from != cur.to) bidiOther = i; + return found; + } + } + } + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar(line.text.charAt(pos))); + return pos; + } + + // This is needed in order to move 'visually' through bi-directional + // text -- i.e., pressing left should make the cursor go left, even + // when in RTL text. The tricky part is the 'jumps', where RTL and + // LTR text touch each other. This often requires the cursor offset + // to move more than one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + function charType(code) { + if (code <= 0xf7) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); + else if (0x6ee <= code && code <= 0x8ac) return "r"; + else if (0x2000 <= code && code <= 0x200b) return "w"; + else if (code == 0x200c) return "b"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function(str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i+1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + var before = (i ? types[i-1] : outerType) == "L"; + var after = (end < len ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} + order.push(new BidiSpan(0, start, i)); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) {} + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) {} + order.splice(at, 0, new BidiSpan(2, nstart, j)); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + if (order[0].level != lst(order).level) + order.push(new BidiSpan(order[0].level, len, len)); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "5.1.1"; + + return CodeMirror; +}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/policy-view.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/policy-view.js new file mode 100644 index 000000000..67e2c7f8a --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/policy-view.js @@ -0,0 +1,128 @@ +/* + * 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. + */ + +var skipStep = {}; +var policy = {}; + + +skipStep["policy-platform"] = function (policyPayloadObj) { + console.log(policyPayloadObj); + policy["name"] = policyPayloadObj["policyName"]; + policy["platform"] = policyPayloadObj["profile"]["deviceType"]["name"]; + policy["platformId"] = policyPayloadObj["profile"]["deviceType"]["id"]; + var userRoleInput = $("#user-roles-input"); + var ownershipInput = $("#ownership-input"); + var userInput = $("#users-select-field"); + var actionInput = $("#action-input"); + var policyNameInput = $("#policy-name-input"); + var policyDescriptionInput = $("#policy-description-input"); + userRoleInput.val(policyPayloadObj.roles); + userInput.val(policyPayloadObj.users); + ownershipInput.val(policyPayloadObj.ownershipType); + actionInput.val(policyPayloadObj.compliance); + policyNameInput.val(policyPayloadObj["policyName"]); + policyDescriptionInput.val(policyPayloadObj["description"]); + // updating next-page wizard title with selected platform + $("#policy-heading").text(policy["platform"].toUpperCase() + " POLICY - " + policy["name"].toUpperCase()); + $("#policy-platform").text(policy["platform"].toUpperCase()); + $("#policy-assignment").text(policyPayloadObj.ownershipType); + $("#policy-action").text(policyPayloadObj.compliance.toUpperCase()); + $("#policy-description").text(policyPayloadObj["description"]); + var policyStatus = "Active"; + if(policyPayloadObj["active"] == true && policyPayloadObj["updated"] == true) { + policyStatus = ' Active/Updated'; + } else if(policyPayloadObj["active"] == true && policyPayloadObj["updated"] == false) { + policyStatus = ' Active'; + } else if(policyPayloadObj["active"] == false && policyPayloadObj["updated"] == true) { + policyStatus = ' Inactive/Updated'; + } else if(policyPayloadObj["active"] == false && policyPayloadObj["updated"] == false) { + policyStatus = ' Inactive'; + } + + $("#policy-status").html(policyStatus); + + if(policyPayloadObj.users.length > 0) { + $("#policy-users").text(policyPayloadObj.users.toString().split(",").join(", ")); + } else { + $("#users-row").addClass("hidden"); + } + + if(policyPayloadObj.roles.length > 0) { + $("#policy-roles").text(policyPayloadObj.roles.toString().split(",").join(", ")); + } else { + $("#roles-row").addClass("hidden"); + } + var profileFeaturesList = policyPayloadObj["profile"]["profileFeaturesList"]; + if (profileFeaturesList.length > 0){ + var content = profileFeaturesList[0]["content"]; + var policyDefinitionObj = JSON.parse(content); + window.queryEditor.setValue(policyDefinitionObj["policyDefinition"]); + } +}; + + +// End of functions related to grid-input-view + +/** + * This method will return query parameter value given its name. + * @param name Query parameter name + * @returns {string} Query parameter value + */ +var getParameterByName = function (name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); +}; + +$(document).ready(function () { + + window.queryEditor = CodeMirror.fromTextArea(document.getElementById('policy-definition-input'), { + mode: MIME_TYPE_SIDDHI_QL, + indentWithTabs: true, + smartIndent: true, + lineNumbers: true, + matchBrackets: true, + autofocus: true, + readOnly: true, + extraKeys: { + "Shift-2": function (cm) { + insertStr(cm, cm.getCursor(), '@'); + CodeMirror.showHint(cm, getAnnotationHints); + }, + "Ctrl-Space": "autocomplete" + } + }); + + var policyPayloadObj; + invokerUtil.get( + "/devicemgt_admin/policies/" + getParameterByName("id"), + // on success + function (data) { + // console.log("success: " + JSON.stringify(data)); + data = JSON.parse(data); + policyPayloadObj = data["responseContent"]; + skipStep["policy-platform"](policyPayloadObj); + }, + // on error + function () { + // should be redirected to an error page + } + ); + +}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/sql.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/sql.js new file mode 100644 index 000000000..9f92fbc93 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/public/js/sql.js @@ -0,0 +1,310 @@ +/* + * 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. + */ + +/*Annotations, Annotation Names and relevant tokens*/ +var ANNOTATION_IMPORT = "Import"; +var ANNOTATION_EXPORT = "Export"; + +var ANNOTATION_TOKEN_AT = "@"; +var ANNOTATION_TOKEN_OPENING_BRACKET = "("; +var ANNOTATION_TOKEN_CLOSING_BRACKET = ")"; + +var REGEX_LINE_STARTING_WITH_PLAN = /^@Plan.*/g; +var REGEX_LINE_STARTING_WITH_SINGLE_LINE_COMMENT = /^--.*/g; +var REGEX_LINE_STARTING_WITH_MULTI_LINE_COMMENT = /^\/\*.*\*\//g; +var REGEX_LINE_STARTING_WITH_IMPORT_STATEMENT = /^@Import.*/g; + +var SIDDHI_STATEMENT_DELIMETER = ";"; +var SIDDHI_LINE_BREAK = "\n"; +var SIDDHI_LINE_BREAK_CHARACTER = '\n'; +var SIDDHI_SINGLE_QUOTE = "'"; +var SIDDHI_SPACE_LITERAL = " "; + +var SIDDHI_LITERAL_DEFINE_STREAM = "define stream"; + +var MIME_TYPE_SIDDHI_QL = "text/siddhi-ql"; + + +CodeMirror.defineMode("sql", function (config, parserConfig) { + "use strict"; + + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false":true, "true":true, "null":true}, + builtin = parserConfig.builtin || {}, + keywords = parserConfig.keywords || {}, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date":true, "time":true, "timestamp":true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + support.decimallessFloat == true && stream.eat('.'); + return "number"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if ((ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + return "number"; + } + } else { + stream.eatWhile(/^[_\-\w\d]/); /* Character '-' will also be eaten, to prevent the highlight happening in keywords being embedded in non-keyword strings. For example, 'all' in 'all-nonkeyword' */ + var word = stream.current().toLowerCase(); // Added toLowerCase() to highlight keywords in a case insensitive manner. + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function (stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev:state.context, + indent:stream.indentation(), + col:stream.column(), + type:type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState:function () { + return {tokenize:tokenBase, context:null}; + }, + + token:function (stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent:function (state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + var closing = textAfter.charAt(0) == cx.type; + if (cx.align) return cx.col + (closing ? 0 : 1); + else return cx.indent + (closing ? 0 : config.indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "--" + }; +}); + +(function () { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + } + + ; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywordsWithoutSymbols = "all and as begin by contains define delete end events " + + "every first for from full group having inner insert into join last " + + "left not of on or outer output partition raw return right select snapshot stream table "; + var sqlKeywords = ", : ? # ( ) " + sqlKeywordsWithoutSymbols; + var builtIn = "bool double float int long object string "; + var atoms = "false true null "; + var dateSQL = "days hours milliseconds minutes months seconds "; + var allSqlSuggestions = sqlKeywordsWithoutSymbols + builtIn + atoms + dateSQL; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME(MIME_TYPE_SIDDHI_QL, { + name:"sql", + keywords:set(sqlKeywords), + builtin:set(builtIn), + atoms:set(atoms), + operatorChars:/^[*+%<>!=/]/, + dateSQL:set(dateSQL), + support:set("doubleQuote "), + allSqlSuggestions:set(allSqlSuggestions) + }); +}()); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + functions: + A list of function names you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. + */ \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.hbs new file mode 100644 index 000000000..6cf20df0e --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.hbs @@ -0,0 +1,95 @@ +{{#zone "topCss"}} + {{css "css/codemirror.css"}} +{{/zone}} +{{#zone "contentTitle"}} +
      +
      + +
      +
      +{{/zone}} + + +
      + +
      +
      +
      +
      +
      + Policy Overview +
      + {{#defineZone "policy-detail-properties"}} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + Platform +
      Assignment Group +
      Action upon + non-compliance +
      Status
      Assigned Users
      Assigned Roles
      + {{/defineZone}} +
      + Description +
      +
      +
      +
      +
      + +
      + Profile Information +
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      + +
      +
      + +
      +{{#zone "bottomJs"}} + {{js "js/codemirror.js"}} + {{js "js/sql.js"}} + {{js "js/policy-view.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.js new file mode 100644 index 000000000..36b130ca0 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.js @@ -0,0 +1,25 @@ +/* + * 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("policy-view-edit-unit backend js"); + log.debug("calling policy-view-edit-unit"); + var userModule = require("/app/modules/user.js").userModule; + context.roles = userModule.getRoles().content; + return context; +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.json new file mode 100644 index 000000000..fd2590129 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.view/view.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/css/codemirror.css b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/css/codemirror.css new file mode 100644 index 000000000..e749a5211 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/css/codemirror.css @@ -0,0 +1,342 @@ +/* + * 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. + */ + +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; + left: -30px; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; +} +.CodeMirror.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +@-moz-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@-webkit-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +div.CodeMirror-overwrite div.CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + height: 100%; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; + left: -30px; +} +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + border-right: none; + width: 0; +} + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror ::selection { background: #d7d4f0; } +.CodeMirror ::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/codemirror.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/codemirror.js new file mode 100644 index 000000000..20f3f95ed --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/codemirror.js @@ -0,0 +1,8720 @@ +/* + * 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. + */ + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + module.exports = mod(); + else if (typeof define == "function" && define.amd) // AMD + return define([], mod); + else // Plain browser env + this.CodeMirror = mod(); +})(function() { + "use strict"; + + // BROWSER SNIFFING + + // Kludges for bugs and behavior differences that can't be feature + // detected are enabled based on userAgent etc sniffing. + + var gecko = /gecko\/\d/i.test(navigator.userAgent); + var ie_upto10 = /MSIE \d/.test(navigator.userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); + var ie = ie_upto10 || ie_11up; + var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); + var webkit = /WebKit\//.test(navigator.userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); + var chrome = /Chrome\//.test(navigator.userAgent); + var presto = /Opera\//.test(navigator.userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); + var phantom = /PhantomJS/.test(navigator.userAgent); + + var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + // This is woefully incomplete. Suggestions for alternative methods welcome. + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); + var mac = ios || /Mac/.test(navigator.platform); + var windows = /win/i.test(navigator.platform); + + var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); + if (presto_version) presto_version = Number(presto_version[1]); + if (presto_version && presto_version >= 15) { presto = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); + var captureRightClick = gecko || (ie && ie_version >= 9); + + // Optimize some code when these features are not used. + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + // EDITOR CONSTRUCTOR + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options ? copyObj(options) : {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + setGuttersForLineNumbers(options); + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(doc, options.mode); + this.doc = doc; + + var input = new CodeMirror.inputStyles[options.inputStyle](this); + var display = this.display = new Display(place, doc, input); + display.wrapper.CodeMirror = this; + updateGutters(this); + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + if (options.autofocus && !mobile) display.input.focus(); + initScrollbars(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + }; + + var cm = this; + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); + + registerEventHandlers(this); + ensureGlobalHandlers(); + + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); + + if ((options.autofocus && !mobile) || cm.hasFocus()) + setTimeout(bind(onFocus, this), 20); + else + onBlur(this); + + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](this, options[opt], Init); + maybeUpdateLineNumberWidth(this); + if (options.finishInit) options.finishInit(this); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + endOperation(this); + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + display.lineDiv.style.textRendering = "auto"; + } + + // DISPLAY CONSTRUCTOR + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc, input) { + var d = this; + this.input = input; + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.scrollbarFiller.setAttribute("cm-not-content", "true"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + d.gutterFiller.setAttribute("cm-not-content", "true"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = elt("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + d.sizerWidth = null; + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; + + if (place) { + if (place.appendChild) place.appendChild(d.wrapper); + else place(d.wrapper); + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + d.reportedViewFrom = d.reportedViewTo = doc.first; + // Information about the rendered lines. + d.view = []; + d.renderedView = null; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastWrapHeight = d.lastWrapWidth = 0; + d.updateLineNumbers = null; + + d.nativeBarWidth = d.barHeight = d.barWidth = 0; + d.scrollbarsClipped = false; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + + d.activeTouch = null; + + input.init(d); + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + cm.display.sizerWidth = null; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function(){updateScrollbars(cm);}, 100); + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function(line) { + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + else + return widgetsHeight + th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + updateGutterSpace(cm); + } + + function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth; + cm.display.sizer.style.marginLeft = width + "px"; + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(0, true); + len -= cur.text.length - found.from.ch; + cur = found.to.line; + len += cur.text.length - found.to.ch; + } + return len; + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(found, 1); + } + } + + // SCROLLBARS + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth; + var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + }; + } + + function NativeScrollbars(place, scroll, cm) { + this.cm = cm; + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + place(vert); place(horiz); + + on(vert, "scroll", function() { + if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); + }); + on(horiz, "scroll", function() { + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); + }); + + this.checkedOverlay = false; + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; + } + + NativeScrollbars.prototype = copyObj({ + update: function(measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + var sWidth = measure.nativeBarWidth; + + if (needsV) { + this.vert.style.display = "block"; + this.vert.style.bottom = needsH ? sWidth + "px" : "0"; + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + } else { + this.vert.style.display = ""; + this.vert.firstChild.style.height = "0"; + } + + if (needsH) { + this.horiz.style.display = "block"; + this.horiz.style.right = needsV ? sWidth + "px" : "0"; + this.horiz.style.left = measure.barLeft + "px"; + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.firstChild.style.width = + (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + } else { + this.horiz.style.display = ""; + this.horiz.firstChild.style.width = "0"; + } + + if (!this.checkedOverlay && measure.clientHeight > 0) { + if (sWidth == 0) this.overlayHack(); + this.checkedOverlay = true; + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; + }, + setScrollLeft: function(pos) { + if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; + }, + setScrollTop: function(pos) { + if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; + }, + overlayHack: function() { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + this.horiz.style.minHeight = this.vert.style.minWidth = w; + var self = this; + var barMouseDown = function(e) { + if (e_target(e) != self.vert && e_target(e) != self.horiz) + operation(self.cm, onMouseDown)(e); + }; + on(this.vert, "mousedown", barMouseDown); + on(this.horiz, "mousedown", barMouseDown); + }, + clear: function() { + var parent = this.horiz.parentNode; + parent.removeChild(this.horiz); + parent.removeChild(this.vert); + } + }, NativeScrollbars.prototype); + + function NullScrollbars() {} + + NullScrollbars.prototype = copyObj({ + update: function() { return {bottom: 0, right: 0}; }, + setScrollLeft: function() {}, + setScrollTop: function() {}, + clear: function() {} + }, NullScrollbars.prototype); + + CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; + + function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear(); + if (cm.display.scrollbars.addClass) + rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function() { + if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); + }); + node.setAttribute("cm-not-content", "true"); + }, function(pos, axis) { + if (axis == "horizontal") setScrollLeft(cm, pos); + else setScrollTop(cm, pos); + }, cm); + if (cm.display.scrollbars.addClass) + addClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + function updateScrollbars(cm, measure) { + if (!measure) measure = measureForScrollbars(cm); + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; + updateScrollbarsInner(cm, measure); + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + updateHeightsInViewport(cm); + updateScrollbarsInner(cm, measureForScrollbars(cm)); + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + } + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbarsInner(cm, measure) { + var d = cm.display; + var sizes = d.scrollbars.update(measure); + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = sizes.bottom + "px"; + d.scrollbarFiller.style.width = sizes.right + "px"; + } else d.scrollbarFiller.style.display = ""; + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sizes.bottom + "px"; + d.gutterFiller.style.width = measure.gutterWidth + "px"; + } else d.gutterFiller.style.display = ""; + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewport may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + if (ensureFrom < from) { + from = ensureFrom; + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); + to = ensureTo; + } + } + return {from: from, to: Math.max(to, from + 1)}; + } + + // LINE NUMBERS + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + if (cm.options.fixedGutter && view[i].gutter) + view[i].gutter.style.left = left; + var align = view[i].alignable; + if (align) for (var j = 0; j < align.length; j++) + align[j].style.left = left; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm); + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + } + + // DISPLAY DRAWING + + function DisplayUpdate(cm, viewport, force) { + var display = cm.display; + + this.viewport = viewport; + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport); + this.editorIsHidden = !display.wrapper.offsetWidth; + this.wrapperHeight = display.wrapper.clientHeight; + this.wrapperWidth = display.wrapper.clientWidth; + this.oldDisplayWidth = displayWidth(cm); + this.force = force; + this.dims = getDimensions(cm); + this.events = []; + } + + DisplayUpdate.prototype.signal = function(emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments); + }; + DisplayUpdate.prototype.finish = function() { + for (var i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]); + }; + + function maybeClipScrollbars(cm) { + var display = cm.display; + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; + display.heightForcer.style.height = scrollGap(cm) + "px"; + display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; + display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; + display.scrollbarsClipped = true; + } + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc; + + if (update.editorIsHidden) { + resetView(cm); + return false; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + return false; + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm); + update.dims = getDimensions(cm); + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, update.visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + return false; + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt(); + if (toUpdate > 4) display.lineDiv.style.display = "none"; + patchDisplay(cm, display.updateLineNumbers, update.dims); + if (toUpdate > 4) display.lineDiv.style.display = ""; + display.renderedView = display.view; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + display.gutters.style.height = 0; + + if (different) { + display.lastWrapHeight = update.wrapperHeight; + display.lastWrapWidth = update.wrapperWidth; + startWorker(cm, 400); + } + + display.updateLineNumbers = null; + + return true; + } + + function postUpdateDisplay(cm, update) { + var force = update.force, viewport = update.viewport; + for (var first = true;; first = false) { + if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) { + force = true; + } else { + force = false; + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + break; + } + if (!updateDisplayIfNeeded(cm, update)) break; + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + } + + update.signal(cm, "update", cm); + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + } + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm); + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + update.finish(); + } + } + + function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px"; + var total = measure.docHeight + cm.display.barHeight; + cm.display.heightForcer.style.top = total + "px"; + cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height; + if (cur.hidden) continue; + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + } + var diff = cur.line.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + updateWidgetHeight(cur.rest[j]); + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + line.widgets[i].height = line.widgets[i].node.offsetHeight; + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + var gutterLeft = d.gutters.clientLeft; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; + width[cm.options.gutters[i]] = n.clientWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth}; + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + node.style.display = "none"; + else + node.parentNode.removeChild(node); + return next; + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) cur = rm(cur); + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) cur = rm(cur); + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") updateLineText(cm, lineView); + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); + else if (type == "class") updateLineClasses(lineView); + else if (type == "widget") updateLineWidgets(cm, lineView, dims); + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + lineView.text.parentNode.replaceChild(lineView.node, lineView.text); + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + } + return lineView.node; + } + + function updateLineBackground(lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) cls += " CodeMirror-linebackground"; + if (lineView.background) { + if (cls) lineView.background.className = cls; + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built; + } + return buildLineContent(cm, lineView); + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) lineView.node = built.pre; + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(lineView) { + updateLineBackground(lineView); + if (lineView.line.wrapClass) + ensureLineWrapped(lineView).className = lineView.line.wrapClass; + else if (lineView.node != lineView.text) + lineView.node.className = ""; + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + + "px; width: " + dims.gutterTotalWidth + "px"); + cm.display.input.setUneditable(gutterWrap); + wrap.insertBefore(gutterWrap, lineView.text); + if (lineView.line.gutterClass) + gutterWrap.className += " " + lineView.line.gutterClass; + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + cm.display.lineNumInnerWidth + "px")); + if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + } + } + } + + function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) lineView.alignable = null; + for (var node = lineView.node.firstChild, next; node; node = next) { + var next = node.nextSibling; + if (node.className == "CodeMirror-linewidget") + lineView.node.removeChild(node); + } + insertLineWidgets(cm, lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) lineView.bgClass = built.bgClass; + if (built.textClass) lineView.textClass = built.textClass; + + updateLineClasses(lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(cm, lineView, dims); + return lineView.node; + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); + } + + function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) return; + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); + positionLineWidget(widget, node, lineView, dims); + cm.display.input.setUneditable(node); + if (allowAbove && widget.above) + wrap.insertBefore(node, lineView.gutter || lineView.text); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // POSITION OBJECT + + // A Pos instance represents a position within the text. + var Pos = CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; + + function copyPos(x) {return Pos(x.line, x.ch);} + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } + + // INPUT HANDLING + + function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + } + + function isReadOnly(cm) { + return cm.options.readOnly || cm.doc.cantEdit; + } + + // This will be set to an array of strings when copying, so that, + // when pasting, we know what kind of selections the copied text + // was made out of. + var lastCopied = null; + + function applyTextInput(cm, inserted, deleted, sel) { + var doc = cm.doc; + cm.display.shift = false; + if (!sel) sel = doc.sel; + + var textLines = splitLines(inserted), multiPaste = null; + // When pasing N lines into N selections, insert one line per selection + if (cm.state.pasteIncoming && sel.ranges.length > 1) { + if (lastCopied && lastCopied.join("\n") == inserted) + multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); + else if (textLines.length == sel.ranges.length) + multiPaste = map(textLines, function(l) { return [l]; }); + } + + // Normal behavior is to insert the new text into every selection + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + var from = range.from(), to = range.to(); + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + from = Pos(from.line, from.ch - deleted); + else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + } + var updateInput = cm.curOp.updateInput; + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, + origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + // When an 'electric' character is inserted, immediately trigger a reindent + if (inserted && !cm.state.pasteIncoming && cm.options.electricChars && + cm.options.smartIndent && range.head.ch < 100 && + (!i || sel.ranges[i - 1].head.line != range.head.line)) { + var mode = cm.getModeAt(range.head); + var end = changeEnd(changeEvent); + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indentLine(cm, end.line, "smart"); + break; + } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) + indentLine(cm, end.line, "smart"); + } + } + } + ensureCursorVisible(cm); + cm.curOp.updateInput = updateInput; + cm.curOp.typing = true; + cm.state.pasteIncoming = cm.state.cutIncoming = false; + } + + function copyableRanges(cm) { + var text = [], ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; + ranges.push(lineRange); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); + } + return {text: text, ranges: ranges}; + } + + function disableBrowserMagic(field) { + field.setAttribute("autocorrect", "off"); + field.setAttribute("autocapitalize", "off"); + field.setAttribute("spellcheck", "false"); + } + + // TEXTAREA INPUT STYLE + + function TextareaInput(cm) { + this.cm = cm; + // See input.poll and input.reset + this.prevInput = ""; + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false; + // Self-resetting timeout for the poller + this.polling = new Delayed(); + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false; + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false; + }; + + function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) te.style.width = "1000px"; + else te.setAttribute("wrap", "off"); + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) te.style.border = "1px solid black"; + disableBrowserMagic(te); + return div; + } + + TextareaInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = this.cm; + + // Wraps and hides input textarea + var div = this.wrapper = hiddenTextarea(); + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var te = this.textarea = div.firstChild; + display.wrapper.insertBefore(div, display.wrapper.firstChild); + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) te.style.width = "0px"; + + on(te, "input", function() { + if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; + input.poll(); + }); + + on(te, "paste", function() { + // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 + // Add a char to the end of textarea before paste occur so that + // selection doesn't span to the end of textarea. + if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { + var start = te.selectionStart, end = te.selectionEnd; + te.value += "$"; + // The selection end needs to be set before the start, otherwise there + // can be an intermediate non-empty selection between the two, which + // can override the middle-click paste buffer on linux and cause the + // wrong thing to get pasted. + te.selectionEnd = end; + te.selectionStart = start; + cm.state.fakedLastChar = true; + } + cm.state.pasteIncoming = true; + input.fastPoll(); + }); + + function prepareCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (input.inaccurateSelection) { + input.prevInput = ""; + input.inaccurateSelection = false; + te.value = lastCopied.join("\n"); + selectInput(te); + } + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll); + } else { + input.prevInput = ""; + te.value = ranges.text.join("\n"); + selectInput(te); + } + } + if (e.type == "cut") cm.state.cutIncoming = true; + } + on(te, "cut", prepareCopyCut); + on(te, "copy", prepareCopyCut); + + on(display.scroller, "paste", function(e) { + if (eventInWidget(display, e)) return; + cm.state.pasteIncoming = true; + input.focus(); + }); + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function(e) { + if (!eventInWidget(display, e)) e_preventDefault(e); + }); + }, + + prepareSelection: function() { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc; + var result = prepareSelection(cm); + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + } + + return result; + }, + + showSelection: function(drawn) { + var cm = this.cm, display = cm.display; + removeChildrenAndAdd(display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px"; + this.wrapper.style.left = drawn.teLeft + "px"; + } + }, + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + reset: function(typing) { + if (this.contextMenuPending) return; + var minimal, selected, cm = this.cm, doc = cm.doc; + if (cm.somethingSelected()) { + this.prevInput = ""; + var range = doc.sel.primary(); + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + this.textarea.value = content; + if (cm.state.focused) selectInput(this.textarea); + if (ie && ie_version >= 9) this.hasSelection = content; + } else if (!typing) { + this.prevInput = this.textarea.value = ""; + if (ie && ie_version >= 9) this.hasSelection = null; + } + this.inaccurateSelection = minimal; + }, + + getField: function() { return this.textarea; }, + + supportsTouch: function() { return false; }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus(); } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } + }, + + blur: function() { this.textarea.blur(); }, + + resetPosition: function() { + this.wrapper.style.top = this.wrapper.style.left = 0; + }, + + receivedFocus: function() { this.slowPoll(); }, + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + slowPoll: function() { + var input = this; + if (input.pollingFast) return; + input.polling.set(this.cm.options.pollInterval, function() { + input.poll(); + if (input.cm.state.focused) input.slowPoll(); + }); + }, + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + fastPoll: function() { + var missed = false, input = this; + input.pollingFast = true; + function p() { + var changed = input.poll(); + if (!changed && !missed) {missed = true; input.polling.set(60, p);} + else {input.pollingFast = false; input.slowPoll();} + } + input.polling.set(20, p); + }, + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + poll: function() { + var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (!cm.state.focused || (hasSelection(input) && !prevInput) || + isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) + return false; + // See paste handler for more on the fakedLastChar kludge + if (cm.state.pasteIncoming && cm.state.fakedLastChar) { + input.value = input.value.substring(0, input.value.length - 1); + cm.state.fakedLastChar = false; + } + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) return false; + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset(); + return false; + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) prevInput = "\u200b"; + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + + var self = this; + runInOp(cm, function() { + applyTextInput(cm, text.slice(same), prevInput.length - same); + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; + else self.prevInput = text; + }); + return true; + }, + + ensurePolled: function() { + if (this.pollingFast && this.poll()) this.pollingFast = false; + }, + + onKeyPress: function() { + if (ie && ie_version >= 9) this.hasSelection = null; + this.fastPoll(); + }, + + onContextMenu: function(e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea; + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) return; // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + + var oldCSS = te.style.cssText; + input.wrapper.style.position = "absolute"; + te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) + display.input.focus(); + if (webkit) window.scrollTo(null, oldScrollY); + display.input.reset(); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) te.value = input.prevInput = " "; + input.contextMenuPending = true; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; + input.prevInput = selected ? "" : "\u200b"; + te.selectionStart = 1; te.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + input.contextMenuPending = false; + input.wrapper.style.position = "relative"; + te.style.cssText = oldCSS; + if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + var i = 0, poll = function() { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); + else display.input.reset(); + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) prepareSelectAllHack(); + if (captureRightClick) { + e_stop(e); + var mouseup = function() { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + }, + + setUneditable: nothing, + + needsContentAttribute: false + }, TextareaInput.prototype); + + // CONTENTEDITABLE INPUT STYLE + + function ContentEditableInput(cm) { + this.cm = cm; + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; + this.polling = new Delayed(); + this.gracePeriod = false; + } + + ContentEditableInput.prototype = copyObj({ + init: function(display) { + var input = this, cm = input.cm; + var div = input.div = display.lineDiv; + div.contentEditable = "true"; + disableBrowserMagic(div); + + on(div, "paste", function(e) { + var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); + if (pasted) { + e.preventDefault(); + cm.replaceSelection(pasted, null, "paste"); + } + }); + + on(div, "compositionstart", function(e) { + var data = e.data; + input.composing = {sel: cm.doc.sel, data: data, startData: data}; + if (!data) return; + var prim = cm.doc.sel.primary(); + var line = cm.getLine(prim.head.line); + var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); + if (found > -1 && found <= prim.head.ch) + input.composing.sel = simpleSelection(Pos(prim.head.line, found), + Pos(prim.head.line, found + data.length)); + }); + on(div, "compositionupdate", function(e) { + input.composing.data = e.data; + }); + on(div, "compositionend", function(e) { + var ours = input.composing; + if (!ours) return; + if (e.data != ours.startData && !/\u200b/.test(e.data)) + ours.data = e.data; + // Need a small delay to prevent other code (input event, + // selection polling) from doing damage when fired right after + // compositionend. + setTimeout(function() { + if (!ours.handled) + input.applyComposition(ours); + if (input.composing == ours) + input.composing = null; + }, 50); + }); + + on(div, "touchstart", function() { + input.forceCompositionEnd(); + }); + + on(div, "input", function() { + if (input.composing) return; + if (!input.pollContent()) + runInOp(input.cm, function() {regChange(cm);}); + }); + + function onCopyCut(e) { + if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); + if (e.type == "cut") cm.replaceSelection("", null, "cut"); + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = ranges.text; + if (e.type == "cut") { + cm.operation(function() { + cm.setSelections(ranges.ranges, 0, sel_dontScroll); + cm.replaceSelection("", null, "cut"); + }); + } + } + // iOS exposes the clipboard API, but seems to discard content inserted into it + if (e.clipboardData && !ios) { + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData("text/plain", lastCopied.join("\n")); + } else { + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild; + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); + te.value = lastCopied.join("\n"); + var hadFocus = document.activeElement; + selectInput(te); + setTimeout(function() { + cm.display.lineSpace.removeChild(kludge); + hadFocus.focus(); + }, 50); + } + } + on(div, "copy", onCopyCut); + on(div, "cut", onCopyCut); + }, + + prepareSelection: function() { + var result = prepareSelection(this.cm, false); + result.focus = this.cm.state.focused; + return result; + }, + + showSelection: function(info) { + if (!info || !this.cm.display.view.length) return; + if (info.focus) this.showPrimarySelection(); + this.showMultipleSelections(info); + }, + + showPrimarySelection: function() { + var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && + cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) + return; + + var start = posToDOM(this.cm, prim.from()); + var end = posToDOM(this.cm, prim.to()); + if (!start && !end) return; + + var view = this.cm.display.view; + var old = sel.rangeCount && sel.getRangeAt(0); + if (!start) { + start = {node: view[0].measure.map[2], offset: 0}; + } else if (!end) { // FIXME dangerously hacky + var measure = view[view.length - 1].measure; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; + } + + try { var rng = range(start.node, start.offset, end.offset, end.node); } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + sel.removeAllRanges(); + sel.addRange(rng); + if (old && sel.anchorNode == null) sel.addRange(old); + else if (gecko) this.startGracePeriod(); + } + this.rememberSelection(); + }, + + startGracePeriod: function() { + var input = this; + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function() { + input.gracePeriod = false; + if (input.selectionChanged()) + input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); + }, 20); + }, + + showMultipleSelections: function(info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + }, + + rememberSelection: function() { + var sel = window.getSelection(); + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + }, + + selectionInEditor: function() { + var sel = window.getSelection(); + if (!sel.rangeCount) return false; + var node = sel.getRangeAt(0).commonAncestorContainer; + return contains(this.div, node); + }, + + focus: function() { + if (this.cm.options.readOnly != "nocursor") this.div.focus(); + }, + blur: function() { this.div.blur(); }, + getField: function() { return this.div; }, + + supportsTouch: function() { return true; }, + + receivedFocus: function() { + var input = this; + if (this.selectionInEditor()) + this.pollSelection(); + else + runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); + + function poll() { + if (input.cm.state.focused) { + input.pollSelection(); + input.polling.set(input.cm.options.pollInterval, poll); + } + } + this.polling.set(this.cm.options.pollInterval, poll); + }, + + selectionChanged: function() { + var sel = window.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + }, + + pollSelection: function() { + if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + var sel = window.getSelection(), cm = this.cm; + this.rememberSelection(); + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var head = domToPos(cm, sel.focusNode, sel.focusOffset); + if (anchor && head) runInOp(cm, function() { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); + if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; + }); + } + }, + + pollContent: function() { + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); + var from = sel.from(), to = sel.to(); + if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; + + var fromIndex; + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + var fromLine = lineNo(display.view[0].line); + var fromNode = display.view[0].node; + } else { + var fromLine = lineNo(display.view[fromIndex].line); + var fromNode = display.view[fromIndex - 1].node.nextSibling; + } + var toIndex = findViewIndex(cm, to.line); + if (toIndex == display.view.length - 1) { + var toLine = display.viewTo - 1; + var toNode = display.view[toIndex].node; + } else { + var toLine = lineNo(display.view[toIndex + 1].line) - 1; + var toNode = display.view[toIndex + 1].node.previousSibling; + } + + var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } + else break; + } + + var cutFront = 0, cutEnd = 0; + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + ++cutFront; + var newBot = lst(newText), oldBot = lst(oldText); + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)); + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + ++cutEnd; + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); + newText[0] = newText[0].slice(cutFront); + + var chFrom = Pos(fromLine, cutFront); + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input"); + return true; + } + }, + + ensurePolled: function() { + this.forceCompositionEnd(); + }, + reset: function() { + this.forceCompositionEnd(); + }, + forceCompositionEnd: function() { + if (!this.composing || this.composing.handled) return; + this.applyComposition(this.composing); + this.composing.handled = true; + this.div.blur(); + this.div.focus(); + }, + applyComposition: function(composing) { + if (composing.data && composing.data != composing.startData) + operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); + }, + + setUneditable: function(node) { + node.setAttribute("contenteditable", "false"); + }, + + onKeyPress: function(e) { + e.preventDefault(); + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + }, + + onContextMenu: nothing, + resetPosition: nothing, + + needsContentAttribute: true + }, ContentEditableInput.prototype); + + function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line); + if (!view || view.hidden) return null; + var line = getLine(cm.doc, pos.line); + var info = mapFromLineView(view, line, pos.line); + + var order = getOrder(line), side = "left"; + if (order) { + var partPos = getBidiPartAt(order, pos.ch); + side = partPos % 2 ? "right" : "left"; + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left"); + result.offset = result.collapse == "right" ? result.end : result.start; + return result; + } + + function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } + + function domToPos(cm, node, offset) { + var lineNode; + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset]; + if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); + node = null; offset = 0; + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) return null; + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i]; + if (lineView.node == lineNode) + return locateNodeInLineView(lineView, node, offset); + } + } + + function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false; + if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); + if (node == wrapper) { + bad = true; + node = wrapper.childNodes[offset]; + offset = 0; + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line; + return badPos(Pos(lineNo(line), line.text.length), bad); + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node; + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild; + if (offset) offset = textNode.nodeValue.length; + } + while (topNode.parentNode != wrapper) topNode = topNode.parentNode; + var measure = lineView.measure, maps = measure.maps; + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; + return Pos(line, ch); + } + } + } + } + var found = find(textNode, topNode, offset); + if (found) return badPos(found, bad); + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0); + if (found) + return badPos(Pos(found.line, found.ch - dist), bad); + else + dist += after.textContent.length; + } + for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1); + if (found) + return badPos(Pos(found.line, found.ch + dist), bad); + else + dist += after.textContent.length; + } + } + + function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false; + function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text"); + if (cmText != null) { + if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); + text += cmText; + return; + } + var markerID = node.getAttribute("cm-marker"), range; + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + if (found.length && (range = found[0].find())) + text += getBetween(cm.doc, range.from, range.to).join("\n"); + return; + } + if (node.getAttribute("contenteditable") == "false") return; + for (var i = 0; i < node.childNodes.length; i++) + walk(node.childNodes[i]); + if (/^(pre|div|p)$/i.test(node.nodeName)) + closing = true; + } else if (node.nodeType == 3) { + var val = node.nodeValue; + if (!val) return; + if (closing) { + text += "\n"; + closing = false; + } + text += val; + } + } + for (;;) { + walk(from); + if (from == to) break; + from = from.nextSibling; + } + return text; + } + + CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; + + // SELECTION / CURSOR + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + function Selection(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + } + + Selection.prototype = { + primary: function() { return this.ranges[this.primIndex]; }, + equals: function(other) { + if (other == this) return true; + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + for (var i = 0; i < this.ranges.length; i++) { + var here = this.ranges[i], there = other.ranges[i]; + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + } + return true; + }, + deepCopy: function() { + for (var out = [], i = 0; i < this.ranges.length; i++) + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); + return new Selection(out, this.primIndex); + }, + somethingSelected: function() { + for (var i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].empty()) return true; + return false; + }, + contains: function(pos, end) { + if (!end) end = pos; + for (var i = 0; i < this.ranges.length; i++) { + var range = this.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + return i; + } + return -1; + } + }; + + function Range(anchor, head) { + this.anchor = anchor; this.head = head; + } + + Range.prototype = { + from: function() { return minPos(this.anchor, this.head); }, + to: function() { return maxPos(this.anchor, this.head); }, + empty: function() { + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + } + }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex]; + ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) --primIndex; + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex); + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0); + } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} + function clipPosArray(doc, array) { + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); + return out; + } + + // SELECTION UPDATES + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head); + } else { + return new Range(other || head, head); + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); + var newSel = normalizeSelection(out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); + } + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); + else return sel; + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + sel = filterSelectionChange(doc, sel); + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + ensureCursorVisible(doc.cm); + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) return; + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) out = sel.ranges.slice(0, i); + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; + var dir = bias || 1; + doc.cantEdit = false; + search: for (;;) { + var line = getLine(doc, curPos.line); + if (line.markedSpans) { + for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; + var newPos = m.find(dir < 0 ? -1 : 1); + if (cmp(newPos, curPos) == 0) { + newPos.ch += dir; + if (newPos.ch < 0) { + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); + else newPos = null; + } else if (newPos.ch > line.text.length) { + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); + else newPos = null; + } + if (!newPos) { + if (flipped) { + // Driven in a corner -- no valid cursor position found at all + // -- try again *with* clearing, if we didn't already + if (!mayClear) return skipAtomic(doc, pos, bias, true); + // Otherwise, turn off editing until further notice, and return the start of the doc + doc.cantEdit = true; + return Pos(doc.first, 0); + } + flipped = true; newPos = pos; dir = -dir; + } + } + curPos = newPos; + continue search; + } + } + } + return curPos; + } + } + + // SELECTION DRAWING + + function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()); + } + + function prepareSelection(cm, primary) { + var doc = cm.doc, result = {}; + var curFragment = result.cursors = document.createDocumentFragment(); + var selFragment = result.selection = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (primary === false && i == doc.sel.primIndex) continue; + var range = doc.sel.ranges[i]; + var collapsed = range.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + drawSelectionCursor(cm, range, curFragment); + if (!collapsed) + drawSelectionRange(cm, range, selFragment); + } + return result; + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, range, output) { + var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + cursor.style.left = pos.left + "px"; + cursor.style.top = pos.top + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left + "px"; + otherCursor.style.top = pos.other.top + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } + } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left; + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + top = Math.round(top); + bottom = Math.round(bottom); + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + + "px; height: " + (bottom - top) + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = leftSide; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = leftSide; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = rightSide; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < leftSide + 1) left = leftSide; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return {start: start, end: end}; + } + + var sFrom = range.from(), sTo = range.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(leftSide, leftEnd.bottom, null, rightStart.top); + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function() { + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + else if (cm.options.cursorBlinkRate < 0) + display.cursorDiv.style.visibility = "hidden"; + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.viewTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + var changedLines = []; + + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles; + var highlighted = highlightLine(cm, line, state, true); + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) line.styleClasses = newCls; + else if (oldCls) line.styleClasses = null; + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) changedLines.push(doc.frontier); + line.stateAfter = copyState(doc.mode, state); + } else { + processLine(cm, line.text, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + if (changedLines.length) runInOp(cm, function() { + for (var i = 0; i < changedLines.length; i++) + regLineChange(cm, changedLines[i], "text"); + }); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function(line) { + processLine(cm, line.text, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + if (precise) doc.frontier = pos; + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop;} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; + return data; + } + + function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } + function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; + } + function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && displayWidth(cm); + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + heights.push((cur.bottom + next.top) / 2 - rect.top); + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + return {map: lineView.measure.map, cache: lineView.measure.cache}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest[i] == line) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineNo(lineView.rest[i]) > lineN) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view; + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + return cm.display.view[findViewIndex(cm, lineN)]; + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + return ext; + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) + view = null; + else if (view && view.changes) + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + if (!view) + view = updateExternalMeasurement(cm, line); + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + }; + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) ch = -1; + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + prepared.rect = prepared.view.text.getBoundingClientRect(); + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) prepared.cache[key] = found; + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom}; + } + + var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; + + function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + var mStart = map[i], mEnd = map[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) collapse = "right"; + } + if (start != null) { + node = map[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + collapse = bias; + if (bias == "left" && start == 0) + while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; + collapse = "left"; + } + if (bias == "right" && start == mEnd - mStart) + while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; + collapse = "right"; + } + break; + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; + } + + function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); + var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { + rect = node.parentNode.getBoundingClientRect(); + } else if (ie && cm.options.lineWrapping) { + var rects = range(node, start, end).getClientRects(); + if (rects.length) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = nullRect; + } else { + rect = range(node, start, end).getBoundingClientRect() || nullRect; + } + if (rect.left || rect.right || start == 0) break; + end = start; + start = start - 1; + collapse = "right"; + } + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) collapse = bias = "right"; + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = node.getBoundingClientRect(); + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; + else + rect = nullRect; + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + for (var i = 0; i < heights.length - 1; i++) + if (mid < heights[i]) break; + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot}; + if (!rect.left && !rect.right) result.bogus = true; + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + + return result; + } + + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + return rect; + var scaleX = screen.logicalXDPI / screen.deviceXDPI; + var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY}; + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + lineView.measure.caches[i] = {}; + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + clearLineMeasurementCacheFor(cm.display.view[i]); + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"/null (editor), "window", + // or "page". + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"/null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0, pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return {left: left, right: left, top: top, bottom: top + lineObj.height}; + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, outside, xRel) { + var pos = Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + var lineObj = getLine(doc, lineN); + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(0, true); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineN = lineNo(lineObj = mergedPos.to.line); + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (;;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var xDiff = x - (ch == from ? fromX : toX); + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, + xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + } + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var operationGroup = null; + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + }; + if (operationGroup) { + operationGroup.ops.push(cm.curOp); + } else { + cm.curOp.ownsGroup = operationGroup = { + ops: [cm.curOp], + delayedCallbacks: [] + }; + } + } + + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + callbacks[i](); + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); + } + } while (i < callbacks.length); + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp, group = op.ownsGroup; + if (!group) return; + + try { fireCallbacksForOps(group); } + finally { + operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + group.ops[i].cm.curOp = null; + endOperations(group); + } + } + + // The DOM updates done when an operation finishes are batched so + // that the minimum number of relayouts are required. + function endOperations(group) { + var ops = group.ops; + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R1(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W1(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R2(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W2(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_finish(ops[i]); + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; + maybeClipScrollbars(cm); + if (op.updateMaxLine) findMaxLine(cm); + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping; + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + } + + function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) updateHeightsInViewport(cm); + + op.barMeasure = measureForScrollbars(cm); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; + cm.display.sizerWidth = op.adjustWidthTo; + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + } + + if (op.updatedDisplay || op.selectionChanged) + op.preparedSelection = display.input.prepareSelection(); + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + if (op.maxScrollLeft < cm.doc.scrollLeft) + setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); + cm.display.maxLineChanged = false; + } + + if (op.preparedSelection) + cm.display.input.showSelection(op.preparedSelection); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); + if (op.updatedDisplay || op.startHeight != cm.doc.height) + updateScrollbars(cm, op.barMeasure); + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + cm.display.input.reset(op.typing); + if (op.focus && op.focus == activeElt()) ensureFocus(op.cm); + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; + + if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + display.wheelStartX = display.wheelStartY = null; + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); + display.scrollbars.setScrollTop(doc.scrollTop); + display.scroller.scrollTop = doc.scrollTop; + } + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); + display.scrollbars.setScrollLeft(doc.scrollLeft); + display.scroller.scrollLeft = doc.scrollLeft; + alignHorizontally(cm); + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + if (display.wrapper.offsetHeight) + doc.scrollTop = cm.display.scroller.scrollTop; + + // Fire change events, and delayed event handlers + if (op.changeObjs) + signal(cm, "changes", cm, op.changeObjs); + if (op.update) + op.update.finish(); + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) return f(); + startOperation(cm); + try { return f(); } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function() { + if (cm.curOp) return f.apply(cm, arguments); + startOperation(cm); + try { return f.apply(cm, arguments); } + finally { endOperation(cm); } + }; + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function() { + if (this.curOp) return f.apply(this, arguments); + startOperation(this); + try { return f.apply(this, arguments); } + finally { endOperation(this); } + }; + } + function docMethodOp(f) { + return function() { + var cm = this.cm; + if (!cm || cm.curOp) return f.apply(this, arguments); + startOperation(cm); + try { return f.apply(this, arguments); } + finally { endOperation(cm); } + }; + } + + // VIEW TRACKING + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array; + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + if (!lendiff) lendiff = 0; + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + display.updateLineNumbers = from; + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + resetView(cm); + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut = viewCuttingPoint(cm, from, from, -1); + if (cut) { + display.view = display.view.slice(0, cut.index); + display.viewTo = cut.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + ext.lineN += lendiff; + else if (from < ext.lineN + ext.size) + display.externalMeasured = null; + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + display.externalMeasured = null; + + if (line < display.viewFrom || line >= display.viewTo) return; + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) return; + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) arr.push(type); + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) return null; + n -= cm.display.viewFrom; + if (n < 0) return null; + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) return i; + } + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + return {index: index, lineN: newN}; + for (var i = 0, n = cm.display.viewFrom; i < index; i++) + n += view[i].size; + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) return null; + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) return null; + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return {index: index, lineN: newN}; + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + else if (display.viewFrom < from) + display.view = display.view.slice(findViewIndex(cm, from)); + display.viewFrom = from; + if (display.viewTo < to) + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + else if (display.viewTo > to) + display.view = display.view.slice(0, findViewIndex(cm, to)); + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + } + return dirty; + } + + // EVENT HANDLERS + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + on(d.scroller, "dblclick", operation(cm, function(e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = cm.findWordAt(pos); + extendSelection(cm.doc, word.anchor, word.head); + })); + else + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0}; + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); + prevTouch = d.activeTouch; + prevTouch.end = +new Date; + } + }; + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) return false; + var touch = e.touches[0]; + return touch.radiusX <= 1 && touch.radiusY <= 1; + } + function farAway(touch, other) { + if (other.left == null) return true; + var dx = other.left - touch.left, dy = other.top - touch.top; + return dx * dx + dy * dy > 20 * 20; + } + on(d.scroller, "touchstart", function(e) { + if (!isMouseLikeTouchEvent(e)) { + clearTimeout(touchFinished); + var now = +new Date; + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null}; + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX; + d.activeTouch.top = e.touches[0].pageY; + } + } + }); + on(d.scroller, "touchmove", function() { + if (d.activeTouch) d.activeTouch.moved = true; + }); + on(d.scroller, "touchend", function(e) { + var touch = d.activeTouch; + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range; + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + range = new Range(pos, pos); + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + range = cm.findWordAt(pos); + else // Triple tap + range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); + cm.setSelection(range.anchor, range.head); + cm.focus(); + e_preventDefault(e); + } + finishTouch(); + }); + on(d.scroller, "touchcancel", finishTouch); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function() { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + d.dragFunctions = { + simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, + start: function(e){onDragStart(cm, e);}, + drop: operation(cm, onDrop) + }; + + var inp = d.input.getField(); + on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); + on(inp, "keydown", operation(cm, onKeyDown)); + on(inp, "keypress", operation(cm, onKeyPress)); + on(inp, "focus", bind(onFocus, cm)); + on(inp, "blur", bind(onBlur, cm)); + } + + function dragDropChanged(cm, value, old) { + var wasOn = old && old != CodeMirror.Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.simple); + toggle(cm.display.scroller, "dragover", funcs.simple); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + + // Called when the window resizes + function onResize(cm) { + var d = cm.display; + if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) + return; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.scrollbarsClipped = false; + cm.setSize(); + } + + // MOUSE EVENTS + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + return true; + } + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; + + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null; } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords; + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + var cm = this, display = cm.display; + if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function(){display.scroller.draggable = true;}, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + window.focus(); + + switch (e_button(e)) { + case 1: + if (start) + leftButtonDown(cm, e, start); + else if (e_target(e) == display.scroller) + e_preventDefault(e); + break; + case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; + if (start) extendSelection(cm.doc, start); + setTimeout(function() {display.input.focus();}, 20); + e_preventDefault(e); + break; + case 3: + if (captureRightClick) onContextMenu(cm, e); + else delayBlurEvent(cm); + break; + } + } + + var lastClick, lastDoubleClick; + function leftButtonDown(cm, e, start) { + if (ie) setTimeout(bind(ensureFocus, cm), 0); + else cm.curOp.focus = activeElt(); + + var now = +new Date, type; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple"; + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + } else { + type = "single"; + lastClick = {time: now, pos: start}; + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && + type == "single" && (contained = sel.contains(start)) > -1 && + !sel.ranges[contained].empty()) + leftButtonStartDrag(cm, e, start, modifier); + else + leftButtonSelect(cm, e, start, type, modifier); + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display; + var dragEnd = operation(cm, function(e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + if (!modifier) + extendSelection(cm.doc, start); + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + setTimeout(function() {document.body.focus(); display.input.focus();}, 20); + else + display.input.focus(); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc; + e_preventDefault(e); + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + ourRange = ranges[ourIndex]; + else + ourRange = new Range(start, start); + } else { + ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; + } + + if (e.altKey) { + type = "rect"; + if (!addNew) ourRange = new Range(start, start); + start = posFromMouse(cm, e, true, true); + ourIndex = -1; + } else if (type == "double") { + var word = cm.findWordAt(start); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, word.anchor, word.head); + else + ourRange = word; + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, line.anchor, line.head); + else + ourRange = line; + } else { + ourRange = extendRange(doc, ourRange, start); + } + + if (!addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex == -1) { + ourIndex = ranges.length; + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); + startSel = doc.sel; + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) return; + lastPos = pos; + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + else if (text.length > leftPos) + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + } + if (!ranges.length) ranges.push(new Range(start, start)); + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var anchor = oldRange.anchor, head = pos; + if (type != "single") { + if (type == "double") + var range = cm.findWordAt(pos); + else + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); + } else { + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); + } + } + var ranges = startSel.ranges.slice(0); + ranges[ourIndex] = new Range(clipPos(doc, anchor), head); + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, type == "rect"); + if (!cur) return; + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt(); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function() { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + counter = Infinity; + e_preventDefault(e); + display.input.focus(); + off(document, "mousemove", move); + off(document, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function(e) { + if (!e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent, signalfn) { + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; + if (prevent) e_preventDefault(e); + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalfn(cm, type, cm, line, gutter, e); + return e_defaultPrevented(e); + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true, signalLater); + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || isReadOnly(cm)) return; + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function(file, i) { + var reader = new FileReader; + reader.onload = operation(cm, function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(cm.doc, pos); + var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + } + }); + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(function() {cm.display.input.focus();}, 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) + var selected = cm.listSelections(); + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) for (var i = 0; i < selected.length; ++i) + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); + cm.replaceSelection(text, "around", "paste"); + cm.display.input.focus(); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + e.dataTransfer.setData("Text", cm.getSelection()); + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) img.parentNode.removeChild(img); + } + } + + // SCROLL EVENTS + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplaySimple(cm, {top: val}); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + cm.display.scrollbars.setScrollTop(val); + if (gecko) updateDisplaySimple(cm); + startWorker(cm, 100); + } + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + cm.display.scrollbars.setScrollLeft(val); + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1/3; + + var wheelEventDelta = function(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + return {x: dx, y: dy}; + }; + CodeMirror.wheelEventPixels = function(e) { + var delta = wheelEventDelta(e); + delta.x *= wheelPixelsPerUnit; + delta.y *= wheelPixelsPerUnit; + return delta; + }; + + function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + if (!(dx && scroll.scrollWidth > scroll.clientWidth || + dy && scroll.scrollHeight > scroll.clientHeight)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer; + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplaySimple(cm, {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function() { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // KEY EVENTS + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled(); + var prevShift = cm.display.shift, done = false; + try { + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) cm.display.shift = false; + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); + if (result) return result; + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm); + } + + var stopSeq = new Delayed; + function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq; + if (seq) { + if (isModifierKey(name)) return "handled"; + stopSeq.set(50, function() { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null; + cm.display.input.reset(); + } + }); + name = seq + " " + name; + } + var result = lookupKeyForEditor(cm, name, handle); + + if (result == "multi") + cm.state.keySeq = name; + if (result == "handled") + signalLater(cm, "keyHandled", cm, name, e); + + if (result == "handled" || result == "multi") { + e_preventDefault(e); + restartBlink(cm); + } + + if (seq && !result && /\'$/.test(name)) { + e_preventDefault(e); + return true; + } + return !!result; + } + + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + var name = keyName(e, true); + if (!name) return false; + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) + || dispatchKey(cm, name, e, function(b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); + } + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, + function(b) { return doHandleBinding(cm, b, true); }); + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + cm.curOp.focus = activeElt(); + if (signalDOMEvent(cm, e)) return; + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection("", null, "cut"); + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + showCrossHair(cm); + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (e.keyCode == 16) this.doc.sel.shift = false; + signalDOMEvent(this, e); + } + + function onKeyPress(e) { + var cm = this; + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (handleCharBinding(cm, e, ch)) return; + cm.display.input.onKeyPress(e); + } + + // FOCUS/BLUR EVENTS + + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function() { + if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } + }, 100); + } + + function onFocus(cm) { + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset(); + if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 + } + cm.display.input.receivedFocus(); + } + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.delayingBlurEvent) return; + + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; + cm.display.input.onContextMenu(e); + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) return false; + return gutterEvent(cm, e, "gutterContextMenu", false, signal); + } + + // UPDATING + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + var changeEnd = CodeMirror.changeEnd = function(change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) return pos; + if (cmp(pos, change.to) <= 0) return changeEnd(change); + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; + return Pos(line, ch); + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(out, doc.sel.primIndex); + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + return Pos(nw.line, pos.ch - old.ch + nw.ch); + else + return Pos(nw.line + (pos.line - old.line), pos.ch); + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex); + } + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function() { this.canceled = true; } + }; + if (update) obj.update = function(from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits) return; + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + for (var i = 0; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + break; + } + if (i == source.length) return; + hist.lastOrigin = hist.lastSelOrigin = null; + + for (;;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}); + return; + } + selAfter = event; + } + else break; + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({changes: antiChanges, generation: hist.generation}); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return; + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) return; + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function(range) { + return new Range(Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch)); + }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + regLineChange(doc.cm, l, "gutter"); + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); + else updateDoc(doc, change, spans); + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function(line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + signalCursorActivity(cm); + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (change.full) + regChange(cm); + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + regLineChange(cm, from.line, "text"); + else + regChange(cm, from.line, to.line + 1, lendiff); + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) signalLater(cm, "change", cm, obj); + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}); + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, coords) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) return; + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + + coords.left + "px; width: 2px;"); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) margin = 0; + for (var limit = 0; limit < 5; limit++) { + var changed = false, coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + Math.min(coords.top, endCoords.top) - margin, + Math.max(coords.left, endCoords.left), + Math.max(coords.bottom, endCoords.bottom) + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) break; + } + return coords; + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = displayHeight(cm), result = {}; + if (y2 - y1 > screen) y2 = y1 + screen; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var tooWide = x2 - x1 > screenw; + if (tooWide) x2 = x1 + screenw; + if (x1 < 10) + result.scrollLeft = 0; + else if (x1 < screenleft) + result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); + else if (x2 > screenw + screenleft - 3) + result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; + return result; + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollPos(cm, left, top) { + if (left != null || top != null) resolveScrollToPos(cm); + if (left != null) + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + if (top != null) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(), from = cur, to = cur; + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; + to = Pos(cur.line, cur.ch + 1); + } + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos; + if (range) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + Math.min(from.top, to.top) - range.margin, + Math.max(from.right, to.right), + Math.max(from.bottom, to.bottom) + range.margin); + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + } + + // API UTILITIES + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) how = "add"; + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) how = "prev"; + else state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass || indentation > 150) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i, new Range(pos, pos)); + break; + } + } + } + line.stateAfter = null; + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); + return line; + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break; + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function() { + for (var i = kill.length - 1; i >= 0; i--) + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); + ensureCursorVisible(cm); + }); + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + var possible = true; + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return (possible = false); + } else ch = next; + return true; + } + + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) type = "s"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), origDir, true); + if (!possible) result.hitSide = true; + return result; + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (;;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + // EDITOR METHODS + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus();}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function(option) {return this.options[option];}, + getDoc: function() {return this.doc;}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function(spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: methodOp(function(how) { + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); + var start = Math.max(end, from.line); + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + indentLine(this, j, how); + var newRanges = this.doc.sel.ranges; + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise); + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true); + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) type = styles[2]; + else for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else { type = styles[mid * 2 + 2]; break; } + } + var cut = type ? type.indexOf("cm-overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0]; + }, + + getHelpers: function(pos, type) { + var found = []; + if (!helpers.hasOwnProperty(type)) return found; + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) found.push(help[mode[type]]); + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) found.push(val); + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i = 0; i < help._global.length; i++) { + var cur = help._global[i]; + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) + found.push(cur.val); + } + return found; + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary(); + if (start == null) pos = range.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? range.from() : range.to(); + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function(line, mode) { + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + + (end ? this.doc.height - heightAtLine(lineObj) : 0); + }, + + defaultTextHeight: function() { return textHeight(this.display); }, + defaultCharWidth: function() { return charWidth(this.display); }, + + setGutterMarker: methodOp(function(line, gutterID, value) { + return changeLine(this.doc, line, "gutter", function(line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: methodOp(function(gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regLineChange(cm, i, "gutter"); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + lineInfo: function(line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets}; + }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + node.setAttribute("cm-ignore-events", "true"); + this.display.input.setUneditable(node); + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + return commands[cmd](this); + }, + + findPosH: function(from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: methodOp(function(dir, unit) { + var cm = this; + cm.extendSelectionsBy(function(range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + else + return dir < 0 ? range.from() : range.to(); + }, sel_move); + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + doc.replaceSelection("", null, "+delete"); + else + deleteNearSelection(this, function(range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; + }); + }), + + findPosV: function(from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: methodOp(function(dir, unit) { + var cm = this, doc = this.doc, goals = []; + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function(range) { + if (collapse) + return dir < 0 ? range.from() : range.to(); + var headPos = cursorCoords(cm, range.head, "div"); + if (range.goalColumn != null) headPos.left = range.goalColumn; + goals.push(headPos.left); + var pos = findPosV(cm, headPos, dir, unit); + if (unit == "page" && range == doc.sel.primary()) + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); + return pos; + }, sel_move); + if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + doc.sel.ranges[i].goalColumn = goals[i]; + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = this.getHelper(pos, "wordChars"); + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function(ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + else + rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function() { return this.display.input.getField() == activeElt(); }, + + scrollTo: methodOp(function(x, y) { + if (x != null || y != null) resolveScrollToPos(this); + if (x != null) this.curOp.scrollLeft = x; + if (y != null) this.curOp.scrollTop = y; + }), + getScrollInfo: function() { + var scroller = this.display.scroller; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; + if (margin == null) margin = this.options.cursorScrollMargin; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; + } + if (!range.to) range.to = range.from; + range.margin = margin || 0; + + if (range.from.line != null) { + resolveScrollToPos(this); + this.curOp.scrollToPos = range; + } else { + var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + Math.min(range.from.top, range.to.top) - range.margin, + Math.max(range.from.right, range.to.right), + Math.max(range.from.bottom, range.to.bottom) + range.margin); + this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + }), + + setSize: methodOp(function(width, height) { + var cm = this; + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) cm.display.wrapper.style.width = interpret(width); + if (height != null) cm.display.wrapper.style.height = interpret(height); + if (cm.options.lineWrapping) clearLineMeasurementCache(this); + var lineNo = cm.display.viewFrom; + cm.doc.iter(lineNo, cm.display.viewTo, function(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } + ++lineNo; + }); + cm.curOp.forceUpdate = true; + signal(cm, "refresh", this); + }), + + operation: function(f){return runInOp(this, f);}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + this.display.input.reset(); + this.scrollTo(doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; + signalLater(this, "swapDoc", this, old); + return old; + }), + + getInputField: function(){return this.display.input.getField();}, + getWrapperElement: function(){return this.display.wrapper;}, + getScrollerElement: function(){return this.display.scroller;}, + getGutterElement: function(){return this.display.gutters;} + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + // Functions to run when options are changed. + var optionHandlers = CodeMirror.optionHandlers = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + } + + // Passed to option handlers when there is no old value. + var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function(cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != CodeMirror.Init) cm.refresh(); + }); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); + option("electricChars", true); + option("inputStyle", mobile ? "contenteditable" : "textarea", function() { + throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME + }, true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function(cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", function(cm, val, old) { + var next = getKeyMap(val); + var prev = old != CodeMirror.Init && getKeyMap(old); + if (prev && prev.detach) prev.detach(cm, next); + if (next.attach) next.attach(cm, prev || null); + }); + option("extraKeys", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function(cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); + option("scrollbarStyle", "native", function(cm) { + initScrollbars(cm); + updateScrollbars(cm); + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); + }, true); + option("lineNumbers", false, function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); + + option("readOnly", false, function(cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) cm.display.input.reset(); + } + }); + option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); + option("dragDrop", true, dragDropChanged); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.input.resetPosition(); + }); + + option("tabindex", null, function(cm, val) { + cm.display.input.getField().tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; + }; + + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") found = {name: found}; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; + }; + + // Minimal default mode. + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function(name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({pred: predicate, val: value}); + }; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because nested + // modes need to do this for their inner modes. + + var copyState = CodeMirror.copyState = function(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + }; + + var startState = CodeMirror.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + }; + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + CodeMirror.innerMode = function(mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; + }; + + // STANDARD COMMANDS + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, + singleSelection: function(cm) { + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + }, + killLine: function(cm) { + deleteNearSelection(cm, function(range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + return {from: range.head, to: Pos(range.head.line + 1, 0)}; + else + return {from: range.head, to: Pos(range.head.line, len)}; + } else { + return {from: range.from(), to: range.to()}; + } + }); + }, + deleteLine: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; + }); + }, + delLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), to: range.from()}; + }); + }, + delWrappedLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var leftPos = cm.coordsChar({left: 0, top: top}, "div"); + return {from: leftPos, to: range.from()}; + }); + }, + delWrappedLineRight: function(cm) { + deleteNearSelection(cm, function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + return {from: range.from(), to: rightPos }; + }); + }, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + undoSelection: function(cm) {cm.undoSelection();}, + redoSelection: function(cm) {cm.redoSelection();}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + goLineStart: function(cm) { + cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1}); + }, + goLineStartSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + return lineStartSmart(cm, range.head); + }, {origin: "+move", bias: 1}); + }, + goLineEnd: function(cm) { + cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1}); + }, + goLineRight: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + }, sel_move); + }, + goLineLeft: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: 0, top: top}, "div"); + }, sel_move); + }, + goLineLeftSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + var pos = cm.coordsChar({left: 0, top: top}, "div"); + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); + return pos; + }, sel_move); + }, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goGroupRight: function(cm) {cm.moveH(1, "group");}, + goGroupLeft: function(cm) {cm.moveH(-1, "group");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharBefore: function(cm) {cm.deleteH(-1, "char");}, + delCharAfter: function(cm) {cm.deleteH(1, "char");}, + delWordBefore: function(cm) {cm.deleteH(-1, "word");}, + delWordAfter: function(cm) {cm.deleteH(1, "word");}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, + delGroupAfter: function(cm) {cm.deleteH(1, "group");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t");}, + insertSoftTab: function(cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); + } + cm.replaceSelections(spaces); + }, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.execCommand("insertTab"); + }, + transposeChars: function(cm) { + runInOp(cm, function() { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) + cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); + }, + newlineAndIndent: function(cm) { + runInOp(cm, function() { + var len = cm.listSelections().length; + for (var i = 0; i < len; i++) { + var range = cm.listSelections()[i]; + cm.replaceRange("\n", range.anchor, range.head, "+input"); + cm.indentLine(range.from().line + 1, null, true); + ensureCursorVisible(cm); + } + }); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; + var alt, ctrl, shift, cmd; + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; + else if (/^a(lt)?$/i.test(mod)) alt = true; + else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; + else if (/^s(hift)$/i.test(mod)) shift = true; + else throw new Error("Unrecognized modifier name: " + mod); + } + if (alt) name = "Alt-" + name; + if (ctrl) name = "Ctrl-" + name; + if (cmd) name = "Cmd-" + name; + if (shift) name = "Shift-" + name; + return name; + } + + // This is a kludge to keep keymaps mostly working as raw objects + // (backwards compatibility) while at the same time support features + // like normalization and multi-stroke key bindings. It compiles a + // new normalized keymap, and then updates the old object to reflect + // this. + CodeMirror.normalizeKeyMap = function(keymap) { + var copy = {}; + for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname]; + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; + if (value == "...") { delete keymap[keyname]; continue; } + + var keys = map(keyname.split(" "), normalizeKeyName); + for (var i = 0; i < keys.length; i++) { + var val, name; + if (i == keys.length - 1) { + name = keyname; + val = value; + } else { + name = keys.slice(0, i + 1).join(" "); + val = "..."; + } + var prev = copy[name]; + if (!prev) copy[name] = val; + else if (prev != val) throw new Error("Inconsistent bindings for " + name); + } + delete keymap[keyname]; + } + for (var prop in copy) keymap[prop] = copy[prop]; + return keymap; + }; + + var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + return lookupKey(key, map.fallthrough, handle, context); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); + if (result) return result; + } + } + }; + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + var isModifierKey = CodeMirror.isModifierKey = function(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + }; + + // Look up the name of a key as indicated by an event object. + var keyName = CodeMirror.keyName = function(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) return false; + var base = keyNames[event.keyCode], name = base; + if (name == null || event.altGraphKey) return false; + if (event.altKey && base != "Alt") name = "Alt-" + name; + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; + if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; + return name; + }; + + function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val; + } + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function(textarea, options) { + options = options ? copyObj(options) : {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabIndex) + options.tabindex = textarea.tabIndex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + options.finishInit = function(cm) { + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + }; + + textarea.style.display = "none"; + var cm = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + var nextMarkerId = 0; + + var TextMarker = CodeMirror.TextMarker = function(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + this.id = ++nextMarkerId; + }; + eventMixin(TextMarker); + + // Clear the marker. + TextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + else if (cm) { + if (span.to != null) max = lineNo(line); + if (span.from != null) min = lineNo(line); + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(this.lines[i]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm.doc); + } + if (cm) signalLater(cm, "markerCleared", cm, this); + if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function(side, lineObj) { + if (side == null && this.type == "bookmark") side = 1; + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) return from; + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) return to; + } + } + return from && {from: from, to: to}; + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function() { + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) return; + runInOp(cm, function() { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + updateLineHeight(line, line.height + dHeight); + } + }); + }; + + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function(line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) return markTextShared(doc, from, to, options, type); + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) copyObj(options, marker, false); + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + return marker; + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); + if (options.insertLeft) marker.widgetNode.insertLeft = true; + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + throw new Error("Inserting collapsed marker partially overlapping an existing one"); + sawCollapsedSpans = true; + } + + if (marker.addToHistory) + addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function(line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + updateMaxLine = true; + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.collapsed) + regChange(cm, from.line, to.line + 1); + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); + if (marker.atomic) reCheckSelection(cm.doc); + signalLater(cm, "markerAdded", cm, marker); + } + return marker; + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + markers[i].parent = this; + }; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function(side, lineObj) { + return this.primary.find(side, lineObj); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function(doc) { + if (widget) options.widgetNode = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function(m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } + return nw; + } + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } + return nw; + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + if (change.full) return null; + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + // Make sure we didn't create any zero-length spans + if (first) first = clearEmptySpans(first); + if (last && last != first) last = clearEmptySpans(last); + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + spans.splice(i--, 1); + } + if (!spans.length) return null; + return spans; + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function(line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + newParts.push({from: p.from, to: m.from}); + if (dto > 0 || !mk.inclusiveRight && !dto) + newParts.push({from: m.to, to: p.to}); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) return lenDiff; + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) return -fromCmp; + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) return toCmp; + return b.id - a.id; + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) continue; + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || + fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) + return true; + } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = merged.find(-1, true).line; + return line; + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + (lines || (lines = [])).push(line); + } + return lines; + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) return lineN; + return lineNo(vis); + } + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) return lineN; + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) return lineN; + while (merged = collapsedSpanAtEnd(line)) + line = merged.find(1, true).line; + return lineNo(line) + 1; + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.widgetNode) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + // LINE WIDGETS + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.doc = doc; + this.node = node; + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + addToScrollPos(cm, null, diff); + } + + LineWidget.prototype.clear = function() { + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) line.widgets = null; + var height = widgetHeight(this); + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) runInOp(cm, function() { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + }); + }; + LineWidget.prototype.changed = function() { + var oldH = this.height, cm = this.doc.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(line, line.height + diff); + if (cm) runInOp(cm, function() { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + }); + }; + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + var cm = widget.doc.cm; + if (!cm) return 0; + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; + if (widget.noHScroll) + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) cm.display.alignWidgets = true; + changeLine(doc, handle, "widget", function(line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, null, widget.height); + cm.curOp.forceUpdate = true; + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + Line.prototype.lineNo = function() { return lineNo(this); }; + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + function extractLineClasses(type, output) { + if (type) for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) break; + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + output[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + output[prop] += " " + lineClass[2]; + } + return type; + } + + function callBlankLine(mode, state) { + if (mode.blankLine) return mode.blankLine(state); + if (!mode.innerMode) return; + var inner = CodeMirror.innerMode(mode, state); + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + } + + function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; + var style = mode.token(stream, state); + if (stream.pos > stream.start) return style; + } + throw new Error("Mode " + mode.name + " failed to advance stream."); + } + + // Utility for getTokenAt and getLineTokens + function takeToken(cm, pos, precise, asArray) { + function getObj(copy) { + return {start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state}; + } + + var doc = cm.doc, mode = doc.mode, style; + pos = clipPos(doc, pos); + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); + var stream = new StringStream(line.text, cm.options.tabSize), tokens; + if (asArray) tokens = []; + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos; + style = readToken(mode, stream, state); + if (asArray) tokens.push(getObj(true)); + } + return asArray ? tokens : getObj(); + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + var inner = cm.options.addModeClass && [null]; + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); + } + if (inner) { + var mName = inner[0].name; + if (mName) style = "m-" + (style ? mName + " " + style : mName); + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 50000); + f(curStart, curStyle); + } + curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 characters + var pos = Math.min(stream.pos, curStart + 50000); + f(pos, curStyle); + curStart = pos; + } + } + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function(end, style) { + st.push(end, style); + }, lineClasses, forceToEnd); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function(end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i+1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, "cm-overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; + } + } + }, lineClasses); + } + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; + } + + function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + line.styles = result.styles; + if (result.classes) line.styleClasses = result.classes; + else if (line.styleClasses) line.styleClasses = null; + if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; + } + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "") callBlankLine(mode, state); + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + readToken(mode, stream, state); + stream.start = stream.pos; + } + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) return null; + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")); + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = {pre: elt("pre", [content]), content: content, + col: 0, pos: 0, cm: cm, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order; + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) + builder.addToken = buildTokenBadBidi(builder.addToken, order); + builder.map = []; + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + if (line.styleClasses.textClass) + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); + (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + // See issue #2901 + if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) + builder.content.className = "cm-tab-wrap-hack"; + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + + return builder; + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); + return token; + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) return; + var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; + var special = builder.cm.state.specialChars, mustWrap = false; + if (!special.test(text)) { + builder.col += text.length; + var content = document.createTextNode(displayText); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) mustWrap = true; + builder.pos += text.length; + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt.setAttribute("role", "presentation"); + txt.setAttribute("cm-text", "\t"); + builder.col += tabWidth; + } else { + var txt = builder.cm.options.specialCharPlaceholder(m[0]); + txt.setAttribute("cm-text", m[0]); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt); + builder.pos++; + } + } + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle, css); + if (title) token.title = title; + return builder.content.appendChild(token); + } + builder.content.appendChild(content); + } + + function splitSpaces(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function(builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (;;) { + // Find the part that overlaps with the start of this text + for (var i = 0; i < order.length; i++) { + var part = order[i]; + if (part.to > start && part.from <= start) break; + } + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) builder.map.push(builder.pos, builder.pos + size, widget); + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + widget = builder.content.appendChild(document.createElement("span")); + widget.setAttribute("cm-marker", marker.id); + } + if (widget) { + builder.cm.display.input.setUneditable(widget); + builder.content.appendChild(widget); + } + builder.pos += size; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i+=2) + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = ""; + collapsed = null; nextChange = Infinity; + var foundBookmarks = []; + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (sp.from <= pos && (sp.to == null || sp.to > pos)) { + if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } + if (m.className) spanStyle += " " + m.className; + if (m.css) css = m.css; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m); + } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return; + } + if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + function linesFor(start, end) { + for (var i = start, result = []; i < end; ++i) + result.push(new Line(text[i], spansFor(i), estimateHeight)); + return result; + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)); + doc.remove(text.length, doc.size - text.length); + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + var added = linesFor(1, text.length - 1); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + var added = linesFor(1, text.length - 1); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, height = 0; i < lines.length; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + // Remove the n lines at offset 'at'. + removeInner: function(at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + // Helper used to collapse a small branch into a single leaf. + collapse: function(lines) { + lines.push.apply(lines, this.lines); + }, + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + }, + // Used to iterate over a part of the tree. + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + removeInner: function(at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + }, + insertInner: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + // When a node has grown, check whether it should be split. + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function(at, n, op) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: splitLines(code), origin: "setValue", full: true}, true); + setSelection(this, simpleSelection(top)); + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(line); + }, + + lineCount: function() {return this.size;}, + firstLine: function() {return this.first;}, + lastLine: function() {return this.first + this.size - 1;}, + + clipPos: function(pos) {return clipPos(this, pos);}, + + getCursor: function(start) { + var range = this.sel.primary(), pos; + if (start == null || start == "head") pos = range.head; + else if (start == "anchor") pos = range.anchor; + else if (start == "end" || start == "to" || start === false) pos = range.to(); + else pos = range.from(); + return pos; + }, + listSelections: function() { return this.sel.ranges; }, + somethingSelected: function() {return this.sel.somethingSelected();}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads, options)); + }), + extendSelectionsBy: docMethodOp(function(f, options) { + extendSelections(this, map(this.sel.ranges, f), options); + }), + setSelections: docMethodOp(function(ranges, primary, options) { + if (!ranges.length) return; + for (var i = 0, out = []; i < ranges.length; i++) + out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); + setSelection(this, normalizeSelection(out, primary), options); + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + }), + + getSelection: function(lineSep) { + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) return lines; + else return lines.join(lineSep || "\n"); + }, + getSelections: function(lineSep) { + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) sel = sel.join(lineSep || "\n"); + parts[i] = sel; + } + return parts; + }, + replaceSelection: function(code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + dup[i] = code; + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i = changes.length - 1; i >= 0; i--) + makeChange(this, changes[i]); + if (newSel) setSelectionReplaceHistory(this, newSel); + else if (this.cm) ensureCursorVisible(this.cm); + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + + setExtending: function(val) {this.extend = val;}, + getExtending: function() {return this.extend;}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; + return {undo: done, redo: undone}; + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (classTest(cls).test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(classTest(cls)); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + removeLineWidget: function(widget) { widget.clear(); }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function(line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line|| + lineNo == to.line && span.from > to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function(options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy; + }, + unlinkDoc: function(other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode;}, + getEditor: function() {return this.cm;} + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments);}; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) findMaxLine(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + for (var chunk = doc; !chunk.lines;) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function(line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) for (var n = line; n; n = n.parent) n.height += diff; + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0; i < chunk.children.length; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = this.lastSelOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); + return histChange; + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) array.pop(); + else break; + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done); + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done); + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done); + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, ore are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + pushSelectionToHistory(doc.sel, hist.done); + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) hist.done.shift(); + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = hist.lastSelOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + hist.done[hist.done.length - 1] = sel; + else + pushSelectionToHistory(sel, hist.done); + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastSelOp = opId; + if (options && options.clearRedo !== false) + clearSelectionEvents(hist.undone); + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + dest.push(sel); + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue; + } + var changes = event.changes, newChanges = []; + copy.push({changes: newChanges}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue; + } + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT UTILITIES + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + var e_preventDefault = CodeMirror.e_preventDefault = function(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + }; + var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + }; + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var on = CodeMirror.on = function(emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + }; + + var off = CodeMirror.off = function(emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + for (var i = 0; i < arr.length; ++i) + if (arr[i] == f) { arr.splice(i, 1); break; } + } + }; + + var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + }; + + var orphanDelayedCallbacks = null; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + function signalLater(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); + } + function bnd(f) {return function(){f.apply(null, args);};}; + for (var i = 0; i < arr.length; ++i) + list.push(bnd(arr[i])); + } + + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) return; + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + set.push(arr[i]); + } + + function hasHandler(emitter, type) { + var arr = emitter._handlers && emitter._handlers[type]; + return arr && arr.length > 0; + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerGap = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + // Reused option objects for setSelection & friends + var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; + + function Delayed() {this.id = null;} + Delayed.prototype.set = function(ms, f) { + clearTimeout(this.id); + this.id = setTimeout(f, ms); + }; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + }; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) nextTab = string.length; + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + return pos + Math.min(skipped, goal - col); + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) return pos; + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length-1]; } + + var selectInput = function(node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + else if (ie) // Suppress mysterious IE10 errors + selectInput = function(node) { try { node.select(); } catch(_e) {} }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + if (array[i] == elt) return i; + return -1; + } + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); + return out; + } + + function nothing() {} + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + nothing.prototype = base; + inst = new nothing(); + } + if (props) copyObj(props, inst); + return inst; + }; + + function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args);}; + } + + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var isWordCharBasic = CodeMirror.isWordChar = function(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + }; + function isWordChar(ch, helper) { + if (!helper) return isWordCharBasic(ch); + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; + return helper.test(ch); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + var range; + if (document.createRange) range = function(node, start, end, endNode) { + var r = document.createRange(); + r.setEnd(endNode || node, end); + r.setStart(node, start); + return r; + }; + else range = function(node, start, end) { + var r = document.body.createTextRange(); + try { r.moveToElementText(node.parentNode); } + catch(e) { return r; } + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r; + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + var contains = CodeMirror.contains = function(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + child = child.parentNode; + if (parent.contains) + return parent.contains(child); + do { + if (child.nodeType == 11) child = child.host; + if (child == parent) return true; + } while (child = child.parentNode); + }; + + function activeElt() { return document.activeElement; } + // Older versions of IE throws unspecified error when touching + // document.activeElement in some cases (during loading, in iframe) + if (ie && ie_version < 11) activeElt = function() { + try { return document.activeElement; } + catch(e) { return document.body; } + }; + + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } + var rmClass = CodeMirror.rmClass = function(node, cls) { + var current = node.className; + var match = classTest(cls).exec(current); + if (match) { + var after = current.slice(match.index + match[0].length); + node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + } + }; + var addClass = CodeMirror.addClass = function(node, cls) { + var current = node.className; + if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; + }; + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; + return b; + } + + // WINDOW-WIDE EVENTS + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) return; + var byClass = document.body.getElementsByClassName("CodeMirror"); + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) f(cm); + } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) return; + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; + forEachCodeMirror(onResize); + }, 100); + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function() { + forEachCodeMirror(onBlur); + }); + } + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + node.setAttribute("cm-text", ""); + return node; + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) return badBidiRects; + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) + var r1 = range(txt, 1, 2).getBoundingClientRect(); + return badBidiRects = (r1.right - r0.right < 3); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function() { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function"; + })(); + + var badZoomedRects = null; + function hasBadZoomedRects(measure) { + if (badZoomedRects != null) return badZoomedRects; + var node = removeChildrenAndAdd(measure, elt("span", "x")); + var normal = node.getBoundingClientRect(); + var fromRange = range(node, 0, 1).getBoundingClientRect(); + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; + } + + // KEY NAMES + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line = getLine(cm.doc, lineN); + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + lineN = null; + } + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN == null ? lineNo(line) : lineN, ch); + } + function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line); + var line = getLine(cm.doc, start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; + return Pos(start.line, inWS ? 0 : firstNonWS); + } + return start; + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + bidiOther = null; + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) return i; + if ((cur.from == pos || cur.to == pos)) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + if (cur.from != cur.to) bidiOther = found; + return i; + } else { + if (cur.from != cur.to) bidiOther = i; + return found; + } + } + } + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar(line.text.charAt(pos))); + return pos; + } + + // This is needed in order to move 'visually' through bi-directional + // text -- i.e., pressing left should make the cursor go left, even + // when in RTL text. The tricky part is the 'jumps', where RTL and + // LTR text touch each other. This often requires the cursor offset + // to move more than one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + function charType(code) { + if (code <= 0xf7) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); + else if (0x6ee <= code && code <= 0x8ac) return "r"; + else if (0x2000 <= code && code <= 0x200b) return "w"; + else if (code == 0x200c) return "b"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function(str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i+1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + var before = (i ? types[i-1] : outerType) == "L"; + var after = (end < len ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} + order.push(new BidiSpan(0, start, i)); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) {} + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) {} + order.splice(at, 0, new BidiSpan(2, nstart, j)); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + if (order[0].level != lst(order).level) + order.push(new BidiSpan(order[0].level, len, len)); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "5.1.1"; + + return CodeMirror; +}); \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/policy-create.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/policy-create.js new file mode 100644 index 000000000..84e988643 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/policy-create.js @@ -0,0 +1,670 @@ +/* + * 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. + */ + +var validateStep = {}; +var stepForwardFrom = {}; +var stepBackFrom = {}; +var policy = {}; +var configuredOperations = []; +var deviceTypeLabel; + +/** + * Method to update the visibility of grouped input. + * @param domElement HTML grouped-input element with class name "grouped-input" + */ +var updateGroupedInputVisibility = function (domElement) { + if ($(".parent-input:first", domElement).is(":checked")) { + if ($(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).removeClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', false); + }); + } else { + if (!$(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).addClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', true); + }); + } +}; + +/** + * Checks if provided number is valid against a range. + * + * @param numberInput Number Input + * @param min Minimum Limit + * @param max Maximum Limit + * @returns {boolean} Returns true if input is within the specified range + */ +var inputIsValidAgainstRange = function (numberInput, min, max) { + return (numberInput == min || (numberInput > min && numberInput < max) || numberInput == max); +}; + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param input Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +var inputIsValidAgainstRegExp = function (regExp, input) { + return regExp.test(input); +}; + +validateStep["policy-profile"] = function () { + return true; +}; + +stepForwardFrom["policy-profile"] = function () { + policy["profile"] = operationModule.generateProfile(policy["platform"], configuredOperations); + // updating next-page wizard title with selected platform + $("#policy-criteria-page-wizard-title").text("ADD " + deviceTypeLabel + " POLICY"); +}; + +stepBackFrom["policy-profile"] = function () { + // reinitialize configuredOperations + configuredOperations = []; + // clearing already-loaded platform specific hidden-operations html content from the relevant div + // so that, the wrong content would not be shown at the first glance, in case + // the user selects a different platform + $(".wr-advance-operations").html( + "
      " + + "
      " + + "     " + + "" + + "    " + + "Loading Platform Features . . ." + + "
      " + + "
      " + + "
      " + ); +}; + +stepForwardFrom["policy-criteria"] = function () { + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(':radio')) { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + policy["selectedUsers"] = $("#users-input").val(); + } else if ($(this).attr("id") == "user-roles-radio-btn") { + policy["selectedUserRoles"] = $("#user-roles-input").val(); + } + } + } + }); + policy["selectedNonCompliantAction"] = $("#action-input").find(":selected").data("action"); + policy["selectedOwnership"] = $("#ownership-input").val(); + // updating next-page wizard title with selected platform + $("#policy-naming-page-wizard-title").text("ADD " + deviceTypeLabel + " POLICY"); +}; + +/** + * Checks if provided input is valid against provided length range. + * + * @param input Alphanumeric or non-alphanumeric input + * @param minLength Minimum Required Length + * @param maxLength Maximum Required Length + * @returns {boolean} Returns true if input matches the provided minimum length and maximum length + */ +var inputIsValidAgainstLength = function (input, minLength, maxLength) { + var length = input.length; + return (length == minLength || (length > minLength && length < maxLength) || length == maxLength); +}; + +validateStep["policy-naming"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length. Please check."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-naming-publish"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length. Please check."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-naming-publish"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + savePolicy(policy, "publish"); +}; +stepForwardFrom["policy-naming"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + savePolicy(policy, "save"); +}; + +var savePolicy = function (policy, state) { + var profilePayloads = [{ + "featureCode": "CONFIG", + "deviceTypeId": policy["platformId"], + "content": {"policyDefinition": window.queryEditor.getValue()} + }]; + + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": "ANY", + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"], + "name": policy["platform"] + }, + "profileFeaturesList": profilePayloads + } + }; + + if (policy["selectedUsers"]) { + payload["users"] = policy["selectedUsers"]; + } else if (policy["selectedUserRoles"]) { + payload["roles"] = policy["selectedUserRoles"]; + } else { + payload["users"] = []; + payload["roles"] = []; + } + + var serviceURL; + if (state == "save") { + serviceURL = "/devicemgt_admin/policies/inactive-policy" + } else if (state == "publish") { + serviceURL = "/devicemgt_admin/policies/active-policy" + } + invokerUtil.post( + serviceURL, + payload, + function () { + $(".add-policy").addClass("hidden"); + $(".policy-naming").addClass("hidden"); + $(".policy-message").removeClass("hidden"); + if (state == "publish") { + publishToDevice(); + } + }, + function (err) { + console.log(err); + } + ); +}; + +function publishToDevice() { + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": "ANY", + "deviceId": getParameterByName('deviceId'), + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"], + "name": policy["platform"] + }, + "policyDefinition": window.queryEditor.getValue(), + "policyDescription": policy["description"] + } + }; + + var successCallback = function (data, status) { + console.log("Data: " + data + "\nStatus: " + status); + }; + + var data = { + url: "/devicemgt/api/policies/add", + type: "POST", + contentType: "application/json", + accept: "application/json", + success: successCallback, + data: JSON.stringify(payload) + }; + + $.ajax(data).fail(function (jqXHR) { + console.log("Error: " + jqXHR); + }); + +} + +// Start of functions related to grid-input-view + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var setId = function (addFormContainer) { + $(addFormContainer).find("[data-add-form-clone]").each(function (i) { + $(this).attr("id", $(this).attr("data-add-form-clone").slice(1) + "-" + (i + 1)); + if ($(this).find(".index").length > 0) { + $(this).find(".index").html(i + 1); + } + }); +}; + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var showHideHelpText = function (addFormContainer) { + var helpText = "[data-help-text=add-form]"; + if ($(addFormContainer).find("[data-add-form-clone]").length > 0) { + $(addFormContainer).find(helpText).hide(); + } else { + $(addFormContainer).find(helpText).show(); + } +}; + +function formatRepo(user) { + if (user.loading) { + return user.text + } + if (!user.username) { + return; + } + var markup = '
      ' + + '
      ' + + '
      ' + + '
      ' + user.username + '
      '; + if (user.firstname) { + markup += '
      ' + user.firstname + '
      '; + } + if (user.emailAddress) { + markup += '
      ' + user.emailAddress + '
      '; + } + markup += '
      '; + return markup; +} + +function formatRepoSelection(user) { + return user.username || user.text; +} + +// End of functions related to grid-input-view + + +$(document).ready(function () { + window.queryEditor = CodeMirror.fromTextArea(document.getElementById('policy-definition-input'), { + mode: MIME_TYPE_SIDDHI_QL, + indentWithTabs: true, + smartIndent: true, + lineNumbers: true, + matchBrackets: true, + autofocus: true, + extraKeys: { + "Shift-2": function (cm) { + insertStr(cm, cm.getCursor(), '@'); + CodeMirror.showHint(cm, getAnnotationHints); + }, + "Ctrl-Space": "autocomplete" + } + }); + + $("#users-input").select2({ + multiple: true, + tags: true, + ajax: { + url: window.location.origin + "/devicemgt/api/invoker/execute/", + method: "POST", + dataType: 'json', + delay: 250, + id: function (user) { + return user.username; + }, + data: function (params) { + var postData = {}; + postData.actionMethod = "GET"; + postData.actionUrl = "/devicemgt_admin/users"; + postData.actionPayload = JSON.stringify({ + q: params.term, // search term + page: params.page + }); + + return JSON.stringify(postData); + }, + processResults: function (data, page) { + var newData = []; + $.each(data.responseContent, function (index, value) { + value.id = value.username; + newData.push(value); + }); + return { + results: newData + }; + }, + cache: true + }, + escapeMarkup: function (markup) { + return markup; + }, // let our custom formatter work + minimumInputLength: 1, + templateResult: formatRepo, // omitted for brevity, see the source of this page + templateSelection: formatRepoSelection // omitted for brevity, see the source of this page + }); + + // Adding initial state of wizard-steps. + $("#policy-profile-wizard-steps").html($(".wr-steps").html()); + + policy["platform"] = $("#platform").data("platform"); + policy["platformId"] = $("#platform").data("platform-id"); + deviceTypeLabel = $("#platform").data("platform-label"); + // updating next-page wizard title with selected platform + $("#policy-profile-page-wizard-title").text("ADD " + deviceTypeLabel + " POLICY"); + + $("select.select2[multiple=multiple]").select2({ + "tags": true + }); + + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + + $("input[type='radio'].select-users-radio").change(function () { + if ($("#users-radio-btn").is(":checked")) { + $("#user-roles-select-field").hide(); + $("#users-select-field").show(); + } + if ($("#user-roles-radio-btn").is(":checked")) { + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + } + }); + + // Support for special input type "ANY" on user(s) & user-role(s) selection + $("#user-roles-input").select2({ + "tags": true + }).on("select2:select", function (e) { + if (e.params.data.id == "ANY") { + $(this).val("ANY").trigger("change"); + } else { + $("option[value=ANY]", this).prop("selected", false).parent().trigger("change"); + } + }); + + // Maintains an array of configured features of the profile + var advanceOperations = ".wr-advance-operations"; + $(advanceOperations).on("click", ".wr-input-control.switch", function (event) { + var operationCode = $(this).parents(".operation-data").data("operation-code"); + var operation = $(this).parents(".operation-data").data("operation"); + var operationDataWrapper = $(this).data("target"); + // prevents event bubbling by figuring out what element it's being called from. + if (event.target.tagName == "INPUT") { + var featureConfiguredIcon; + if ($("input[type='checkbox']", this).is(":checked")) { + configuredOperations.push(operationCode); + // when a feature is enabled, if "zero-configured-features" msg is available, hide that. + var zeroConfiguredOperationsErrorMsg = "#policy-profile-main-error-msg"; + if (!$(zeroConfiguredOperationsErrorMsg).hasClass("hidden")) { + $(zeroConfiguredOperationsErrorMsg).addClass("hidden"); + } + // add configured-state-icon to the feature + featureConfiguredIcon = "#" + operation + "-configured"; + if ($(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).removeClass("hidden"); + } + } else { + //splicing the array if operation is present. + var index = $.inArray(operationCode, configuredOperations); + if (index != -1) { + configuredOperations.splice(index, 1); + } + // when a feature is disabled, clearing all its current configured, error or success states + var subErrorMsgWrapper = "#" + operation + "-feature-error-msg"; + var subErrorIcon = "#" + operation + "-error"; + var subOkIcon = "#" + operation + "-ok"; + featureConfiguredIcon = "#" + operation + "-configured"; + + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // reinitializing input fields into the defaults + $(operationDataWrapper + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(operationDataWrapper + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(operationDataWrapper + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(operationDataWrapper + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } + } + }); + + // adding support for cloning multiple profiles per feature with cloneable class definitions + $(advanceOperations).on("click", ".multi-view.add.enabled", function () { + // get a copy of .cloneable and create new .cloned div element + var cloned = "

      " + $(".cloneable", $(this).parent().parent()).html() + "
      "; + // append newly created .cloned div element to panel-body + $(this).parent().parent().append(cloned); + // enable remove action of newly cloned div element + $(".cloned", $(this).parent().parent()).each( + function () { + if ($(".multi-view.remove", this).hasClass("disabled")) { + $(".multi-view.remove", this).removeClass("disabled"); + } + if (!$(".multi-view.remove", this).hasClass("enabled")) { + $(".multi-view.remove", this).addClass("enabled"); + } + } + ); + }); + + $(advanceOperations).on("click", ".multi-view.remove.enabled", function () { + $(this).parent().remove(); + }); + + // enabling or disabling grouped-input based on the status of a parent check-box + $(advanceOperations).on("click", ".grouped-input", function () { + updateGroupedInputVisibility(this); + }); + + // add form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=add-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + var clonedForm = $("[data-add-form=" + $(this).attr("href") + "]").clone(). + find("[data-add-form-element=clone]").attr("data-add-form-clone", $(this).attr("href")); + + // adding class .child-input to capture text-input-array-values + $("input, select", clonedForm).addClass("child-input"); + + $(addFormContainer).append(clonedForm); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + // remove form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=remove-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + + $(this).closest("[data-add-form-element=clone]").remove(); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + $(".wizard-stepper").click(function () { + // button clicked here can be either a continue button or a back button. + var currentStep = $(this).data("current"); + var validationIsRequired = $(this).data("validate"); + var wizardIsToBeContinued; + + if (validationIsRequired) { + wizardIsToBeContinued = validateStep[currentStep](); + } else { + wizardIsToBeContinued = true; + } + + if (wizardIsToBeContinued) { + // When moving back and forth, following code segment will + // remove if there are any visible error-messages. + var errorMsgWrappers = ".alert.alert-danger"; + $(errorMsgWrappers).each( + function () { + if (!$(this).hasClass("hidden")) { + $(this).addClass("hidden"); + } + } + ); + + var nextStep = $(this).data("next"); + var isBackBtn = $(this).data("is-back-btn"); + + // if current button is a continuation... + if (!isBackBtn) { + // initiate stepForwardFrom[*] functions to gather form data. + if (stepForwardFrom[currentStep]) { + stepForwardFrom[currentStep](this); + } + } else { + // initiate stepBackFrom[*] functions to rollback. + if (stepBackFrom[currentStep]) { + stepBackFrom[currentStep](); + } + } + + // following step occurs only at the last stage of the wizard. + if (!nextStep) { + window.location.href = $(this).data("direct"); + } + + // updating next wizard step as current. + $(".itm-wiz").each(function () { + var step = $(this).data("step"); + if (step == nextStep) { + $(this).addClass("itm-wiz-current"); + } else { + $(this).removeClass("itm-wiz-current"); + } + }); + + // adding next update of wizard-steps. + $("#" + nextStep + "-wizard-steps").html($(".wr-steps").html()); + + // hiding current section of the wizard and showing next section. + $("." + currentStep).addClass("hidden"); + $("." + nextStep).removeClass("hidden"); + } + }); +}); + +function getParameterByName(name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/sql.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/sql.js new file mode 100644 index 000000000..9f92fbc93 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/public/js/sql.js @@ -0,0 +1,310 @@ +/* + * 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. + */ + +/*Annotations, Annotation Names and relevant tokens*/ +var ANNOTATION_IMPORT = "Import"; +var ANNOTATION_EXPORT = "Export"; + +var ANNOTATION_TOKEN_AT = "@"; +var ANNOTATION_TOKEN_OPENING_BRACKET = "("; +var ANNOTATION_TOKEN_CLOSING_BRACKET = ")"; + +var REGEX_LINE_STARTING_WITH_PLAN = /^@Plan.*/g; +var REGEX_LINE_STARTING_WITH_SINGLE_LINE_COMMENT = /^--.*/g; +var REGEX_LINE_STARTING_WITH_MULTI_LINE_COMMENT = /^\/\*.*\*\//g; +var REGEX_LINE_STARTING_WITH_IMPORT_STATEMENT = /^@Import.*/g; + +var SIDDHI_STATEMENT_DELIMETER = ";"; +var SIDDHI_LINE_BREAK = "\n"; +var SIDDHI_LINE_BREAK_CHARACTER = '\n'; +var SIDDHI_SINGLE_QUOTE = "'"; +var SIDDHI_SPACE_LITERAL = " "; + +var SIDDHI_LITERAL_DEFINE_STREAM = "define stream"; + +var MIME_TYPE_SIDDHI_QL = "text/siddhi-ql"; + + +CodeMirror.defineMode("sql", function (config, parserConfig) { + "use strict"; + + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false":true, "true":true, "null":true}, + builtin = parserConfig.builtin || {}, + keywords = parserConfig.keywords || {}, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date":true, "time":true, "timestamp":true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + support.decimallessFloat == true && stream.eat('.'); + return "number"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if ((ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + return "number"; + } + } else { + stream.eatWhile(/^[_\-\w\d]/); /* Character '-' will also be eaten, to prevent the highlight happening in keywords being embedded in non-keyword strings. For example, 'all' in 'all-nonkeyword' */ + var word = stream.current().toLowerCase(); // Added toLowerCase() to highlight keywords in a case insensitive manner. + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function (stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev:state.context, + indent:stream.indentation(), + col:stream.column(), + type:type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState:function () { + return {tokenize:tokenBase, context:null}; + }, + + token:function (stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent:function (state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + var closing = textAfter.charAt(0) == cx.type; + if (cx.align) return cx.col + (closing ? 0 : 1); + else return cx.indent + (closing ? 0 : config.indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "--" + }; +}); + +(function () { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + } + + ; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywordsWithoutSymbols = "all and as begin by contains define delete end events " + + "every first for from full group having inner insert into join last " + + "left not of on or outer output partition raw return right select snapshot stream table "; + var sqlKeywords = ", : ? # ( ) " + sqlKeywordsWithoutSymbols; + var builtIn = "bool double float int long object string "; + var atoms = "false true null "; + var dateSQL = "days hours milliseconds minutes months seconds "; + var allSqlSuggestions = sqlKeywordsWithoutSymbols + builtIn + atoms + dateSQL; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME(MIME_TYPE_SIDDHI_QL, { + name:"sql", + keywords:set(sqlKeywords), + builtin:set(builtIn), + atoms:set(atoms), + operatorChars:/^[*+%<>!=/]/, + dateSQL:set(dateSQL), + support:set("doubleQuote "), + allSqlSuggestions:set(allSqlSuggestions) + }); +}()); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + functions: + A list of function names you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. + */ \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.hbs new file mode 100644 index 000000000..4cc6fa272 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.hbs @@ -0,0 +1,255 @@ +{{#zone "topCss"}} + {{css "css/codemirror.css"}} +{{/zone}} + +
      +
      + + + + + + + + +
      +
      +

      ADD POLICY

      +
      +
      +
      +
      +
      +

      Step 2: Configure profile

      +
      + + +
      +
      +
      + +
      +
      +
      +
      + +
      +
      +
      +
      + + +
      +
      +{{#zone "bottomJs"}} + {{js "js/codemirror.js"}} + {{js "js/sql.js"}} + {{js "js/policy-create.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.js b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.js new file mode 100644 index 000000000..925a97ea4 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.js @@ -0,0 +1,47 @@ +/* + * 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("wizard.js"); + var DTYPE_CONF_DEVICE_TYPE_KEY = "deviceType"; + var DTYPE_CONF_DEVICE_TYPE_LABEL_KEY = "label"; + + var userModule = require("/app/modules/user.js")["userModule"]; + var utility = require('/app/modules/utility.js').utility; + var response = userModule.getRoles(); + var wizardPage = {}; + if (response["status"] == "success") { + wizardPage["roles"] = response["content"]; + } + var deviceType = context.uriParams.deviceType; + var typesListResponse = userModule.getPlatforms(); + if (typesListResponse["status"] == "success") { + for (var type in typesListResponse["content"]) { + if (deviceType == typesListResponse["content"][type]["name"]) { + wizardPage["type"] = typesListResponse["content"][type]; + var deviceTypeLabel = deviceType; + var configs = utility.getDeviceTypeConfig(deviceType); + if (configs && configs[DTYPE_CONF_DEVICE_TYPE_KEY][DTYPE_CONF_DEVICE_TYPE_LABEL_KEY]) { + deviceTypeLabel = configs[DTYPE_CONF_DEVICE_TYPE_KEY][DTYPE_CONF_DEVICE_TYPE_LABEL_KEY]; + } + wizardPage["type"]["label"] = deviceTypeLabel; + } + } + } + return wizardPage; +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.json new file mode 100644 index 000000000..fd2590129 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.policy.wizard/wizard.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.hbs b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.hbs new file mode 100644 index 000000000..b1841e186 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.hbs @@ -0,0 +1 @@ +{{#zone "productName"}}{{@app.conf.appName}}{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.json b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.json new file mode 100644 index 000000000..4e30bc074 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.ui/src/main/resources/jaggeryapps/devicemgt/app/units/iot.unit.ui.header.logo/logo.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "index": 29, + "extends": "mdm.unit.ui.header.logo" +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml new file mode 100644 index 000000000..cfdc32dbc --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml @@ -0,0 +1,213 @@ + + + + + + + iot-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot + bundle + WSO2 Carbon - IoT Device Management Common Impl + WSO2 Carbon - IoT Device Management and Control Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Impl Bundle + org.wso2.carbon.device.mgt.iot.internal + + org.jivesoftware.smack.*, + javax.xml.namespace;resolution:=optional, + javax.xml.validation;resolution:=optional, + org.apache.commons.codec.binary, + org.apache.commons.collections.map, + org.apache.http.*, + org.apache.commons.io.*, + org.apache.commons.logging.*, + org.json;version="${commons-json.version}", + org.wso2.carbon.base.*, + org.wso2.carbon.databridge.*, + org.wso2.carbon.user.api, + org.wso2.carbon.user.core.service, + org.osgi.framework, + org.osgi.service.component, + javax.xml.bind.*;resolution:=optional, + javax.naming;resolution:=optional, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers.*;resolution:=optional, + javax.net;resolution:=optional, + javax.net.ssl;resolution:=optional, + javax.crypto, + org.apache.tomcat.util.codec.binary, + org.w3c.dom;resolution:=optional, + org.wso2.carbon.core;version="${carbon.kernel.version.range}", + org.wso2.carbon.utils.*;version="${carbon.kernel.version.range}", + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.core.*, + org.wso2.carbon.context.*;version="${carbon.kernel.version.range}", + org.wso2.carbon.ndatasource.core;version="${carbon.kernel.version.range}", + org.eclipse.paho.client.mqttv3.*;version="${eclipse.paho.version}" + + + !org.wso2.carbon.device.mgt.iot.internal, + org.wso2.carbon.device.mgt.iot.*;version="${project.version}" + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.common + provided + + + + org.json.wso2 + json + + + org.wso2.carbon + org.wso2.carbon.core + + + commons-collections + commons-collections + + + commons-configuration + commons-configuration + + + org.wso2.carbon.analytics-common + org.wso2.carbon.databridge.agent + + + org.wso2.carbon.analytics-common + org.wso2.carbon.databridge.core + + + org.wso2.carbon.commons + org.wso2.carbon.databridge.commons + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + commons-codec.wso2 + commons-codec + + + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/DeviceManagementConfigurationManager.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/DeviceManagementConfigurationManager.java new file mode 100644 index 000000000..00774a3cf --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/DeviceManagementConfigurationManager.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.config.server; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.wso2.carbon.device.mgt.iot.config.server.datasource.ControlQueue; +import org.wso2.carbon.device.mgt.iot.config.server.datasource.DeviceManagementConfiguration; +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; +import org.wso2.carbon.device.mgt.iot.util.IotDeviceManagementUtil; +import org.wso2.carbon.utils.CarbonUtils; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.ValidationEvent; +import javax.xml.bind.ValidationEventHandler; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.io.File; +import java.util.List; + +/** + * Class responsible for the iot device manager configuration initialization. + */ +public class DeviceManagementConfigurationManager { + + private static final Log log = LogFactory.getLog(DeviceManagementConfigurationManager.class); + private static final String DEVICE_MGT_CONFIG_XML_NAME = "devicemgt-config.xml"; + private static final String DEVICE_MGT_ROOT_DIRECTORY = "iot"; + private final String XMLCONFIGS_FILE_LOCATION = + CarbonUtils.getCarbonConfigDirPath() + File.separator + + DEVICE_MGT_ROOT_DIRECTORY + File.separator + DEVICE_MGT_CONFIG_XML_NAME; + private static final String IOT_DEVICE_CONFIG_XSD_NAME = "devicemgt-config.xsd"; + private final String XSDCONFIGS_FILE_LOCATION = + CarbonUtils.getCarbonConfigDirPath() + File.separator + + DEVICE_MGT_ROOT_DIRECTORY + File.separator + IOT_DEVICE_CONFIG_XSD_NAME; + private DeviceManagementConfiguration currentDeviceManagementConfiguration; + private static DeviceManagementConfigurationManager deviceConfigurationManager = + new DeviceManagementConfigurationManager(); + + private DeviceManagementConfigurationManager() { + } + + public static DeviceManagementConfigurationManager getInstance() { + return deviceConfigurationManager; + } + + public void initConfig() throws DeviceControllerException { + try { + SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = sf.newSchema(new File(XSDCONFIGS_FILE_LOCATION)); + + File deviceCloudMgtConfig = new File(XMLCONFIGS_FILE_LOCATION); + Document doc = IotDeviceManagementUtil.convertToDocument(deviceCloudMgtConfig); + JAXBContext deviceCloudContext = JAXBContext.newInstance(DeviceManagementConfiguration.class); + Unmarshaller unmarshaller = deviceCloudContext.createUnmarshaller(); + unmarshaller.setSchema(schema); + unmarshaller.setEventHandler(new IotConfigValidationEventHandler()); + this.currentDeviceManagementConfiguration = (DeviceManagementConfiguration) unmarshaller.unmarshal(doc); + } catch (Exception e) { + String error = "Error occurred while initializing DeviceController configurations"; + log.error(error); + throw new DeviceControllerException(error, e); + } + } + + public DeviceManagementConfiguration getDeviceCloudMgtConfig() { + return currentDeviceManagementConfiguration; + } + + public ControlQueue getControlQueue(String name) { + List controlQueues = currentDeviceManagementConfiguration.getControlQueues().getControlQueue(); + if (controlQueues != null) { + for (ControlQueue controlQueue : controlQueues) { + if (controlQueue.getName().equals(name)) { + return controlQueue; + } + } + } + return null; + } + + private class IotConfigValidationEventHandler implements ValidationEventHandler { + @Override + public boolean handleEvent(ValidationEvent event) { + String error = "\nEVENT" + "\nSEVERITY: " + event.getSeverity() + + "\n MESSAGE: " + event.getMessage() + + "\n LINKED EXCEPTION: " + event.getLinkedException() + + "\n LOCATOR" + + "\n LINE NUMBER: " + event.getLocator().getLineNumber() + + "\n COLUMN NUMBER: " + event.getLocator().getColumnNumber() + + "\n OFFSET: " + event.getLocator().getOffset() + + "\n OBJECT: " + event.getLocator().getObject() + + "\n NODE: " + event.getLocator().getNode() + + "\n URL: " + event.getLocator().getURL(); + log.error(error); + return true; + } + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueue.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueue.java new file mode 100644 index 000000000..145763bfa --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueue.java @@ -0,0 +1,229 @@ + +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.config.server.datasource; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for ControlQueue complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="ControlQueue">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="Name" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="Enabled" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *         <element name="ControlClass" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="Protocol" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="ServerURL" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="Port" type="{http://www.w3.org/2001/XMLSchema}short"/>
      + *         <element name="Username" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="Password" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "ControlQueue", propOrder = { + "name", + "enabled", + "controlClass", + "protocol", + "serverURL", + "port", + "username", + "password" +}) +public class ControlQueue { + + @XmlElement(name = "Name", required = true) + protected String name; + @XmlElement(name = "Enabled") + protected boolean enabled; + @XmlElement(name = "ControlClass", required = true) + protected String controlClass; + @XmlElement(name = "Protocol", required = true) + protected String protocol; + @XmlElement(name = "ServerURL", required = true) + protected String serverURL; + @XmlElement(name = "Port") + protected short port; + @XmlElement(name = "Username", required = true) + protected String username; + @XmlElement(name = "Password", required = true) + protected String password; + + /** + * Gets the value of the name property. + * + * @return possible object is + * {@link String } + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value allowed object is + * {@link String } + */ + public void setName(String value) { + this.name = value; + } + + /** + * Gets the value of the enabled property. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Sets the value of the enabled property. + */ + public void setEnabled(boolean value) { + this.enabled = value; + } + + /** + * Gets the value of the controlClass property. + * + * @return possible object is + * {@link String } + */ + public String getControlClass() { + return controlClass; + } + + /** + * Sets the value of the controlClass property. + * + * @param value allowed object is + * {@link String } + */ + public void setControlClass(String value) { + this.controlClass = value; + } + + /** + * Gets the value of the protocol property. + * + * @return possible object is + * {@link String } + */ + public String getProtocol() { + return protocol; + } + + /** + * Sets the value of the protocol property. + * + * @param value allowed object is + * {@link String } + */ + public void setProtocol(String value) { + this.protocol = value; + } + + /** + * Gets the value of the serverURL property. + * + * @return possible object is + * {@link String } + */ + public String getServerURL() { + return serverURL; + } + + /** + * Sets the value of the serverURL property. + * + * @param value allowed object is + * {@link String } + */ + public void setServerURL(String value) { + this.serverURL = value; + } + + /** + * Gets the value of the port property. + */ + public short getPort() { + return port; + } + + /** + * Sets the value of the port property. + */ + public void setPort(short value) { + this.port = value; + } + + /** + * Gets the value of the username property. + * + * @return possible object is + * {@link String } + */ + public String getUsername() { + return username; + } + + /** + * Sets the value of the username property. + * + * @param value allowed object is + * {@link String } + */ + public void setUsername(String value) { + this.username = value; + } + + /** + * Gets the value of the password property. + * + * @return possible object is + * {@link String } + */ + public String getPassword() { + return password; + } + + /** + * Sets the value of the password property. + * + * @param value allowed object is + * {@link String } + */ + public void setPassword(String value) { + this.password = value; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueuesConfig.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueuesConfig.java new file mode 100644 index 000000000..e7b82ce0b --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ControlQueuesConfig.java @@ -0,0 +1,82 @@ + +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.config.server.datasource; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for ControlQueuesConfig complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="ControlQueuesConfig">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="ControlQueue" type="{}ControlQueue" maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "ControlQueuesConfig", propOrder = { + "controlQueue" +}) +public class ControlQueuesConfig { + + @XmlElement(name = "ControlQueue") + protected List controlQueue; + + /** + * Gets the value of the controlQueue property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the controlQueue property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +     *    getControlQueue().add(newItem);
      +     * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link ControlQueue } + */ + public List getControlQueue() { + if (controlQueue == null) { + controlQueue = new ArrayList(); + } + return this.controlQueue; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/DeviceManagementConfiguration.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/DeviceManagementConfiguration.java new file mode 100644 index 000000000..6194049c4 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/DeviceManagementConfiguration.java @@ -0,0 +1,74 @@ + +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.config.server.datasource; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for DeviceCloudConfig complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="DeviceManagementConfigurations">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="ControlQueues" type="{}ControlQueuesConfig"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "DeviceManagementConfigurations", propOrder = { + "controlQueues" +}) + +@XmlRootElement(name = "DeviceManagementConfigurations") +public class DeviceManagementConfiguration { + @XmlElement(name = "ControlQueues", required = true) + protected ControlQueuesConfig controlQueues; + + /** + * Gets the value of the controlQueues property. + * + * @return possible object is + * {@link ControlQueuesConfig } + */ + public ControlQueuesConfig getControlQueues() { + return controlQueues; + } + + /** + * Sets the value of the controlQueues property. + * + * @param value allowed object is + * {@link ControlQueuesConfig } + */ + public void setControlQueues(ControlQueuesConfig value) { + this.controlQueues = value; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ObjectFactory.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ObjectFactory.java new file mode 100644 index 000000000..9bc313579 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/config/server/datasource/ObjectFactory.java @@ -0,0 +1,69 @@ + +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.config.server.datasource; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.wso2.carbon.device.mgt.iot.common.config.server.configs package. + *

      An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _DeviceCloudConfiguration_QNAME = new QName("", "DeviceManagementConfigurations"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: + * org.wso2.carbon.device.mgt.iot.common.config.server.configs + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link DeviceManagementConfiguration } + */ + public DeviceManagementConfiguration createDeviceCloudConfig() { + return new DeviceManagementConfiguration(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeviceManagementConfiguration }{@code >}} + */ + @XmlElementDecl(namespace = "", name = "DeviceManagementConfigurations") + public JAXBElement createDeviceCloudConfiguration( + DeviceManagementConfiguration value) { + return new JAXBElement(_DeviceCloudConfiguration_QNAME, + DeviceManagementConfiguration.class, null, value); + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/mqtt/MqttConfig.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/mqtt/MqttConfig.java new file mode 100644 index 000000000..26abefe49 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/mqtt/MqttConfig.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.controlqueue.mqtt; + +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.config.server.datasource.ControlQueue; + +public class MqttConfig { + private String mqttQueueEndpoint; + private String mqttQueueUsername; + private String mqttQueuePassword; + private boolean isEnabled; + private static final String MQTT_QUEUE_CONFIG_NAME = "MQTT"; + private static final String LOCALHOST = "localhost"; + private static final String PORT_OFFSET_PROPERTY = "portOffset"; + private ControlQueue mqttControlQueue; + private static MqttConfig mqttConfig = new MqttConfig(); + + public String getMqttQueueEndpoint() { + return mqttQueueEndpoint; + } + + public String getMqttQueueUsername() { + return mqttQueueUsername; + } + + public String getMqttQueuePassword() { + return mqttQueuePassword; + } + + public ControlQueue getMqttControlQueue() { + return mqttControlQueue; + } + + public boolean isEnabled() { + return isEnabled; + } + + public static String getMqttQueueConfigName() { + return MQTT_QUEUE_CONFIG_NAME; + } + + private MqttConfig() { + + mqttControlQueue = DeviceManagementConfigurationManager.getInstance().getControlQueue(MQTT_QUEUE_CONFIG_NAME); + int portOffset = Integer.parseInt(System.getProperty(PORT_OFFSET_PROPERTY)); + String brokerURL = mqttControlQueue.getServerURL(); + + if (portOffset != 0 && brokerURL.contains(LOCALHOST)) { + // if using the internal MB (meaning URL is localhost and there is a portOffset) + // then increment port accordingly + int mqttPort = mqttControlQueue.getPort(); + mqttPort = mqttPort + portOffset; + mqttQueueEndpoint = mqttControlQueue.getServerURL() + ":" + mqttPort; + } else { + mqttQueueEndpoint = mqttControlQueue.getServerURL() + ":" + mqttControlQueue.getPort(); + } + mqttQueueUsername = mqttControlQueue.getUsername(); + mqttQueuePassword = mqttControlQueue.getPassword(); + isEnabled = mqttControlQueue.isEnabled(); + } + public static MqttConfig getInstance() { + return mqttConfig; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppAccount.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppAccount.java new file mode 100644 index 000000000..94c6dd6d5 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppAccount.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.controlqueue.xmpp; + +public class XmppAccount { + + private String username; + private String password; + private String accountName; + private String email; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppConfig.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppConfig.java new file mode 100644 index 000000000..e06ee66f0 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppConfig.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.controlqueue.xmpp; + +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.config.server.datasource.ControlQueue; + +public class XmppConfig { + + private String xmppServerIP; + private int xmppServerPort; + private String xmppEndpoint; + private String xmppUsername; + private String xmppPassword; + private boolean isEnabled; + private static final String XMPP_QUEUE_CONFIG_NAME = "XMPP"; + private final int SERVER_CONNECTION_PORT = 5222; + private ControlQueue xmppControlQueue; + private static XmppConfig xmppConfig = new XmppConfig(); + + public String getXmppServerIP() { + return xmppServerIP; + } + + public int getXmppServerPort() { + return xmppServerPort; + } + + public String getXmppEndpoint() { + return xmppEndpoint; + } + + public String getXmppUsername() { + return xmppUsername; + } + + public String getXmppPassword() { + return xmppPassword; + } + + public ControlQueue getXmppControlQueue() { + return xmppControlQueue; + } + + public boolean isEnabled() { + return isEnabled; + } + + public static String getXmppQueueConfigName() { + return XMPP_QUEUE_CONFIG_NAME; + } + + private XmppConfig() { + xmppControlQueue = DeviceManagementConfigurationManager.getInstance().getControlQueue( + XMPP_QUEUE_CONFIG_NAME); + xmppServerIP = xmppControlQueue.getServerURL(); + int indexOfChar = xmppServerIP.lastIndexOf('/'); + + if (indexOfChar != -1) { + xmppServerIP = xmppServerIP.substring((indexOfChar + 1), xmppServerIP.length()); + } + + xmppServerPort = xmppControlQueue.getPort(); + xmppEndpoint = xmppControlQueue.getServerURL() + ":" + xmppServerPort; + xmppUsername = xmppControlQueue.getUsername(); + xmppPassword = xmppControlQueue.getPassword(); + isEnabled = xmppControlQueue.isEnabled(); + } + + public static XmppConfig getInstance() { + return xmppConfig; + } + + public int getSERVER_CONNECTION_PORT() { + return SERVER_CONNECTION_PORT; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppServerClient.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppServerClient.java new file mode 100644 index 000000000..55c86707d --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/controlqueue/xmpp/XmppServerClient.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.controlqueue.xmpp; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; +import org.json.JSONArray; +import org.json.JSONObject; +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; +import org.wso2.carbon.device.mgt.iot.exception.IoTException; +import org.wso2.carbon.device.mgt.iot.util.IoTUtil; + +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +public class XmppServerClient { + + private static final Log log = LogFactory.getLog(XmppServerClient.class); + private static final String XMPP_SERVER_API_CONTEXT = "/plugins/restapi/v1"; + private static final String XMPP_USERS_API = "/users"; + private static final String XMPP_SESSIONS_API = "/sessions"; + @SuppressWarnings("unused") + private static final String XMPP_GROUPS_API = "/groups"; + @SuppressWarnings("unused") + private static final String APPLICATION_JSON_MT = "application/json"; + private static final String DEVICEMGT_CONFIG_FILE = "devicemgt-config.xml"; + private String xmppEndpoint; + private String xmppUsername; + private String xmppPassword; + private boolean xmppEnabled = false; + + public XmppServerClient() { + } + + public void initControlQueue() { + xmppEndpoint = XmppConfig.getInstance().getXmppEndpoint(); + xmppUsername = XmppConfig.getInstance().getXmppUsername(); + xmppPassword = XmppConfig.getInstance().getXmppPassword(); + xmppEnabled = XmppConfig.getInstance().isEnabled(); + } + + public boolean createXMPPAccount(XmppAccount newUserAccount) throws DeviceControllerException { + if (xmppEnabled) { + String xmppUsersAPIEndpoint = xmppEndpoint + XMPP_SERVER_API_CONTEXT + XMPP_USERS_API; + if (log.isDebugEnabled()) { + log.debug("The Create-UserAccount Endpoint URL of the XMPP Server is set to: " + xmppUsersAPIEndpoint); + } + + String encodedString = xmppUsername + ":" + xmppPassword; + encodedString = new String(Base64.encodeBase64(encodedString.getBytes(StandardCharsets.UTF_8))); + String authorizationHeader = "Basic " + encodedString; + String jsonRequest = "{\n" + + " \"username\": \"" + newUserAccount.getUsername() + "\"," + + " \"password\": \"" + newUserAccount.getPassword() + "\"," + + " \"name\": \"" + newUserAccount.getAccountName() + "\"," + + " \"email\": \"" + newUserAccount.getEmail() + "\"," + + " \"properties\": {" + + " \"property\": [" + + " {" + + " \"@key\": \"console.rows_per_page\"," + + " \"@value\": \"user-summary=8\"" + + " }," + + " {" + + " \"@key\": \"console.order\"," + + " \"@value\": \"session-summary=1\"" + + " }" + + " ]" + + " }" + + "}"; + + StringEntity requestEntity; + try { + requestEntity = new StringEntity(jsonRequest, MediaType.APPLICATION_JSON, + StandardCharsets.UTF_8.toString()); + } catch (UnsupportedEncodingException e) { + return false; + } + + URL xmppUserApiUrl; + try { + xmppUserApiUrl = new URL(xmppUsersAPIEndpoint); + } catch (MalformedURLException e) { + String errMsg = "Malformed XMPP URL + " + xmppUsersAPIEndpoint; + log.error(errMsg); + throw new DeviceControllerException(errMsg); + } + HttpClient httpClient; + try { + httpClient = IoTUtil.getHttpClient(xmppUserApiUrl.getPort(), xmppUserApiUrl.getProtocol()); + } catch (Exception e) { + log.error("Error on getting a http client for port :" + xmppUserApiUrl.getPort() + " protocol :" + + xmppUserApiUrl.getProtocol()); + return false; + } + + HttpPost httpPost = new HttpPost(xmppUsersAPIEndpoint); + httpPost.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); + httpPost.setEntity(requestEntity); + + try { + HttpResponse httpResponse = httpClient.execute(httpPost); + + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { + String response = IoTUtil.getResponseString(httpResponse); + String errorMsg = "XMPP Server returned status: '" + httpResponse.getStatusLine().getStatusCode() + + "' for account creation with error:\n" + response; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg); + } else { + EntityUtils.consume(httpResponse.getEntity()); + return true; + } + } catch (IOException | IoTException e) { + String errorMsg = "Error occured whilst trying a 'POST' at : " + xmppUsersAPIEndpoint; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + + } else { + log.warn(String.format("XMPP set to false in [%s]", DEVICEMGT_CONFIG_FILE)); + return false; + } + } + + public boolean doesXMPPUserAccountExist(String username) throws DeviceControllerException { + if (xmppEnabled) { + String xmppCheckUserAPIEndpoint = xmppEndpoint + XMPP_SERVER_API_CONTEXT + XMPP_USERS_API + "/" + username; + if (log.isDebugEnabled()) { + log.debug("The Check-User-Account Endpoint URL of the XMPP Server is set to: " + + xmppCheckUserAPIEndpoint); + } + + String encodedString = xmppUsername + ":" + xmppPassword; + encodedString = new String(Base64.encodeBase64(encodedString.getBytes(StandardCharsets.UTF_8))); + String authorizationHeader = "Basic " + encodedString; + + URL xmppUserApiUrl; + try { + xmppUserApiUrl = new URL(xmppCheckUserAPIEndpoint); + } catch (MalformedURLException e) { + String errMsg = "Malformed XMPP URL + " + xmppCheckUserAPIEndpoint; + log.error(errMsg); + throw new DeviceControllerException(errMsg, e); + } + + HttpClient httpClient; + try { + httpClient = IoTUtil.getHttpClient(xmppUserApiUrl.getPort(), xmppUserApiUrl.getProtocol()); + } catch (Exception e) { + String errorMsg = "Error on getting a http client for port :" + xmppUserApiUrl.getPort() + + " protocol :" + xmppUserApiUrl.getProtocol(); + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + + HttpGet httpGet = new HttpGet(xmppCheckUserAPIEndpoint); + httpGet.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); + + try { + HttpResponse httpResponse = httpClient.execute(httpGet); + + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + String response = IoTUtil.getResponseString(httpResponse); + if (log.isDebugEnabled()) { + log.debug("XMPP Server returned status: '" + httpResponse.getStatusLine().getStatusCode() + + "' for checking existence of account [" + username + "] with message:\n" + + response + "\nProbably, an account with this username does not exist."); + } + return false; + } + + } catch (IOException | IoTException e) { + String errorMsg = "Error occured whilst trying a 'GET' at : " + xmppCheckUserAPIEndpoint; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + + if (log.isDebugEnabled()) { + log.debug("XMPP Server already has an account for the username - [" + username + "]."); + } + return true; + } else { + String warnMsg = String.format("XMPP set to false in [%s]", DEVICEMGT_CONFIG_FILE); + log.warn(warnMsg); + throw new DeviceControllerException(warnMsg); + } + } + + public JSONArray getAllCurrentUserSessions() throws DeviceControllerException { + if (xmppEnabled) { + JSONArray xmppSessions; + String xmppSessionsAPIEndpoint = xmppEndpoint + XMPP_SERVER_API_CONTEXT + XMPP_SESSIONS_API; + + if (log.isDebugEnabled()) { + log.debug("The Get-Sessions Endpoint URL of the XMPP Server is set to: " + xmppSessionsAPIEndpoint); + } + + String encodedString = xmppUsername + ":" + xmppPassword; + encodedString = new String(Base64.encodeBase64(encodedString.getBytes(StandardCharsets.UTF_8))); + String authorizationHeader = "Basic " + encodedString; + + URL xmppUserApiUrl; + try { + xmppUserApiUrl = new URL(xmppSessionsAPIEndpoint); + } catch (MalformedURLException e) { + String errMsg = "Malformed XMPP URL + " + xmppSessionsAPIEndpoint; + log.error(errMsg); + throw new DeviceControllerException(errMsg, e); + } + + HttpClient httpClient; + try { + httpClient = IoTUtil.getHttpClient(xmppUserApiUrl.getPort(), xmppUserApiUrl.getProtocol()); + } catch (Exception e) { + String errorMsg = "Error on getting a http client for port :" + xmppUserApiUrl.getPort() + + " protocol :" + xmppUserApiUrl.getProtocol(); + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + + HttpGet httpGet = new HttpGet(xmppSessionsAPIEndpoint); + httpGet.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); + httpGet.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON); + + try { + HttpResponse httpResponse = httpClient.execute(httpGet); + + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + String errorMsg = "XMPP Server returned status: '" + httpResponse.getStatusLine().getStatusCode() + + "' for checking current XMPP Sessions."; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg); + } + + String response = IoTUtil.getResponseString(httpResponse); + xmppSessions = new JSONObject(response).getJSONArray("session"); + return xmppSessions; + + } catch (IOException | IoTException e) { + String errorMsg = "Error occured whilst trying a 'GET' at : " + xmppSessionsAPIEndpoint; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + + } else { + String warnMsg = String.format("XMPP set to false in [%s]", DEVICEMGT_CONFIG_FILE); + log.warn(warnMsg); + throw new DeviceControllerException(warnMsg); + } + } + + public void deleteCurrentXmppSessions() throws DeviceControllerException { + JSONArray xmppSessionsArray; + try { + xmppSessionsArray = getAllCurrentUserSessions(); + } catch (DeviceControllerException e) { + if (e.getMessage().contains(DEVICEMGT_CONFIG_FILE)) { + log.warn(String.format("XMPP set to false in [%s]", DEVICEMGT_CONFIG_FILE)); + return; + } else { + throw e; + } + } + + if (xmppSessionsArray.length() != 0) { + String xmppSessionsAPIEndpoint = xmppEndpoint + XMPP_SERVER_API_CONTEXT + XMPP_SESSIONS_API; + String encodedString = xmppUsername + ":" + xmppPassword; + encodedString = new String(Base64.encodeBase64(encodedString.getBytes(StandardCharsets.UTF_8))); + String authorizationHeader = "Basic " + encodedString; + + if (log.isDebugEnabled()) { + log.debug("The Get-Sessions Endpoint URL of the XMPP Server is set to: " + xmppSessionsAPIEndpoint); + } + + URL xmppUserApiUrl; + try { + xmppUserApiUrl = new URL(xmppSessionsAPIEndpoint); + } catch (MalformedURLException e) { + String errMsg = "Malformed XMPP URL + " + xmppSessionsAPIEndpoint; + log.error(errMsg); + throw new DeviceControllerException(errMsg, e); + } + + HttpClient httpClient; + try { + httpClient = IoTUtil.getHttpClient(xmppUserApiUrl.getPort(), xmppUserApiUrl.getProtocol()); + } catch (Exception e) { + String errorMsg = "Error on getting a http client for port :" + xmppUserApiUrl.getPort() + + " protocol :" + xmppUserApiUrl.getProtocol(); + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + + for (int i = 0; i < xmppSessionsArray.length(); i++) { + + String sessionName = xmppSessionsArray.getJSONObject(i).getString("username"); + String xmppUserSessionsAPIEndpoint = xmppSessionsAPIEndpoint + "/" + sessionName; + + HttpDelete httpDelete = new HttpDelete(xmppUserSessionsAPIEndpoint); + httpDelete.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); + + try { + HttpResponse httpResponse = httpClient.execute(httpDelete); + + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + String errorMsg = + "XMPP Server returned status: '" + httpResponse.getStatusLine().getStatusCode() + + "' for checking current XMPP Sessions."; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg); + } + + } catch (IOException e) { + String errorMsg = "Error occured whilst trying a 'DELETE' user-session [" + sessionName + "] " + + "at : " + xmppUserSessionsAPIEndpoint; + log.error(errorMsg); + throw new DeviceControllerException(errorMsg, e); + } + } + } + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/DeviceControllerException.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/DeviceControllerException.java new file mode 100644 index 000000000..c3bce4848 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/DeviceControllerException.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.exception; + +public class DeviceControllerException extends Exception { + + public DeviceControllerException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public DeviceControllerException(Throwable cause) { + super(cause); + } + + public DeviceControllerException(String message, Throwable cause) { + super(message, cause); + } + + public DeviceControllerException(String message) { + super(message); + } + + public DeviceControllerException() { + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/IoTException.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/IoTException.java new file mode 100644 index 000000000..85639cb63 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/IoTException.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.exception; + +public class IoTException extends Exception { + + public IoTException() { + super(); + } + + public IoTException(String message) { + super(message); + } + + public IoTException(String message, Throwable cause) { + super(message, cause); + } + + public IoTException(Throwable cause) { + super(cause); + } + + protected IoTException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/NotImplementedException.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/NotImplementedException.java new file mode 100644 index 000000000..7ce9b3f80 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/NotImplementedException.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.exception; + +public class NotImplementedException extends RuntimeException { + + public NotImplementedException() { + super(); + } + + public NotImplementedException(String message) { + super(message); + } + + public NotImplementedException(String message, Throwable cause) { + super(message, cause); + } + + public NotImplementedException(Throwable cause) { + super(cause); + } + + protected NotImplementedException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/UnauthorizedException.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/UnauthorizedException.java new file mode 100644 index 000000000..1af199b17 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/exception/UnauthorizedException.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.exception; + +public class UnauthorizedException extends Exception { + + public UnauthorizedException(String message) { + super(message); + } + + public UnauthorizedException(String message, Throwable cause) { + super(message, cause); + } + + public UnauthorizedException(Throwable cause) { + super(cause); + } + + public UnauthorizedException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IoTCommonDataHolder.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IoTCommonDataHolder.java new file mode 100644 index 000000000..6ed374350 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IoTCommonDataHolder.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.internal; + +import org.wso2.carbon.base.ServerConfiguration; +import org.wso2.carbon.databridge.core.DataBridgeReceiverService; + +public class IoTCommonDataHolder { + + private static IoTCommonDataHolder thisInstance = new IoTCommonDataHolder(); + String trustStoreLocaiton; + String trustStorePassword; + private IoTCommonDataHolder() { + + } + + public void initialize(){ + setTrustStore(); + } + + public static IoTCommonDataHolder getInstance() { + return thisInstance; + } + + private void setTrustStore(){ + this.trustStoreLocaiton = ServerConfiguration.getInstance().getFirstProperty("Security.TrustStore.Location"); + this.trustStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.TrustStore.Password"); + } + + public String getTrustStoreLocation(){ + return trustStoreLocaiton; + } + + public String getTrustStorePassword(){ + return trustStorePassword; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IotDeviceManagementServiceComponent.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IotDeviceManagementServiceComponent.java new file mode 100644 index 000000000..dadc99f97 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/internal/IotDeviceManagementServiceComponent.java @@ -0,0 +1,100 @@ +/* + * 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.wso2.carbon.device.mgt.iot.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.core.ServerStartupObserver; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient; +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; +import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; +import org.wso2.carbon.utils.ConfigurationContextService; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.internal.IotDeviceManagementServiceComponent" + * immediate="true" + * @scr.reference name="config.context.service" + * interface="org.wso2.carbon.utils.ConfigurationContextService" + * cardinality="0..1" + * policy="dynamic" + * bind="setConfigurationContextService" + * unbind="unsetConfigurationContextService" + */ +public class IotDeviceManagementServiceComponent { + + private static final Log log = LogFactory.getLog(IotDeviceManagementServiceComponent.class); + public static ConfigurationContextService configurationContextService; + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Iot Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + /* Initialize the data source configuration */ + DeviceManagementConfigurationManager.getInstance().initConfig(); + bundleContext.registerService(ServerStartupObserver.class.getName(), new IoTServerStartupListener(), null); + IoTCommonDataHolder.getInstance().initialize(); + if (log.isDebugEnabled()) { + log.debug("Iot Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Iot Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + XmppConfig xmppConfig = XmppConfig.getInstance(); + try { + if (xmppConfig.isEnabled()) { + XmppServerClient xmppServerClient = new XmppServerClient(); + xmppServerClient.initControlQueue(); + xmppServerClient.deleteCurrentXmppSessions(); + } + } catch (DeviceControllerException e) { + String errorMsg = "An error occurred whilst trying to delete all existing XMPP login sessions at " + + "[" + xmppConfig.getXmppEndpoint() + "]."; + log.error(errorMsg, e); + } + + if (log.isDebugEnabled()) { + log.debug("De-activating Iot Device Management Service Component"); + } + } + + protected void setConfigurationContextService(ConfigurationContextService configurationContextService) { + if (log.isDebugEnabled()) { + log.debug("Setting ConfigurationContextService"); + } + + IotDeviceManagementServiceComponent.configurationContextService = configurationContextService; + + } + + protected void unsetConfigurationContextService(ConfigurationContextService configurationContextService) { + if (log.isDebugEnabled()) { + log.debug("Un-setting ConfigurationContextService"); + } + IotDeviceManagementServiceComponent.configurationContextService = null; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/mqtt/PolicyPush.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/mqtt/PolicyPush.java new file mode 100644 index 000000000..9fc4fddd9 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/mqtt/PolicyPush.java @@ -0,0 +1,66 @@ +/* + * 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.wso2.carbon.device.mgt.iot.mqtt; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; + +public class PolicyPush { + + private static final Log log = LogFactory.getLog(PolicyPush.class); + + public boolean pushToMQTT(String topic, String content, String broker, String clientId) { + + byte qos = 2; + MemoryPersistence persistence = new MemoryPersistence(); + + try { + MqttClient me = new MqttClient(broker, clientId, persistence); + MqttConnectOptions connOpts = new MqttConnectOptions(); + connOpts.setCleanSession(true); + if (log.isDebugEnabled()) { + log.debug("Connecting to broker: " + broker); + } + me.connect(connOpts); + if (log.isDebugEnabled()) { + log.debug("Connected"); + log.debug("Publishing message: " + content); + } + MqttMessage message = new MqttMessage(content.getBytes()); + message.setQos(qos); + me.publish(topic, message); + if (log.isDebugEnabled()) { + log.debug("Message published"); + } + me.disconnect(); + if (log.isDebugEnabled()) { + log.debug("Disconnected"); + } + return true; + } catch (MqttException ex) { + log.error("Error occurred when trying to publish to MQTT Queue", ex); + return false; + } + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/DeviceRecord.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/DeviceRecord.java new file mode 100644 index 000000000..5f4d6eb90 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/DeviceRecord.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.sensormgt; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +@XmlRootElement +public class DeviceRecord implements Serializable { + private Map sensorDataList = new HashMap<>(); + + public DeviceRecord(String sensorName, String sensorValue, long time) { + sensorDataList.put(sensorName, new SensorRecord(sensorValue, time)); + } + + @XmlElement + public Map getSensorDataList() { + return sensorDataList; + } + + public void addDeviceRecord(String sensorName, String sensorValue, long time) { + sensorDataList.put(sensorName, new SensorRecord(sensorValue, time)); + } +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorDataManager.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorDataManager.java new file mode 100644 index 000000000..fa1cc7c15 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorDataManager.java @@ -0,0 +1,137 @@ +/* + * 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.wso2.carbon.device.mgt.iot.sensormgt; + +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * This class is used to store latest sensor value readings against a device id in an in-memory map. + */ +public class SensorDataManager { + + private static final SensorDataManager instance = new SensorDataManager(); + private Map deviceMap = new HashMap<>(); + + private SensorDataManager() { + } + + public static SensorDataManager getInstance() { + return instance; + } + + /** + * Store sensor record in a map. + * + * @param deviceId + * @param sensorName + * @param sensorValue + * @param time + * @return if success returns true + */ + public boolean setSensorRecord(String deviceId, String sensorName, String sensorValue, long time) { + DeviceRecord deviceRecord = deviceMap.get(deviceId); + if (deviceRecord == null) { + deviceRecord = new DeviceRecord(sensorName, sensorValue, time); + } else { + deviceRecord.addDeviceRecord(sensorName, sensorValue, time); + } + deviceMap.put(deviceId, deviceRecord); + return true; + } + + /** + * Returns last updated sensor records list for a device + * + * @param deviceId + * @return list of sensor records + */ + public SensorRecord[] getSensorRecords(String deviceId) throws DeviceControllerException { + DeviceRecord deviceRecord = deviceMap.get(deviceId); + if (deviceRecord != null) { + Collection list = deviceRecord.getSensorDataList().values(); + return list.toArray(new SensorRecord[list.size()]); + } + throw new DeviceControllerException("Error: No records found for the device ID: " + deviceId); + } + + /** + * Returns last updated sensor record for a device's sensor + * + * @param deviceId + * @param sensorName + * @return sensor record + */ + public SensorRecord getSensorRecord(String deviceId, String sensorName) throws + DeviceControllerException { + DeviceRecord deviceRecord = deviceMap.get(deviceId); + if (deviceRecord != null) { + SensorRecord sensorRecord = deviceRecord.getSensorDataList().get(sensorName); + if (sensorRecord != null) { + return sensorRecord; + } + throw new DeviceControllerException("Error: No records found for the Device ID: " + deviceId + + " Sensor Name: " + sensorName); + } + throw new DeviceControllerException("Error: No records found for the device ID: " + deviceId); + } + + /** + * Returns last updated sensor value for a device's sensor + * + * @param deviceId + * @param sensorName + * @return sensor reading + */ + public String getSensorRecordValue(String deviceId, String sensorName) throws DeviceControllerException { + DeviceRecord deviceRecord = deviceMap.get(deviceId); + if (deviceRecord != null) { + SensorRecord sensorRecord = deviceRecord.getSensorDataList().get(sensorName); + if (sensorRecord != null) { + return sensorRecord.getSensorValue(); + } + throw new DeviceControllerException("Error: No records found for the Device ID: " + deviceId + + " Sensor Name: " + sensorName); + } + throw new DeviceControllerException("Error: No records found for the device ID: " + deviceId); + } + + /** + * Returns last updated sensor value reading time for a device's sensor + * + * @param deviceId + * @param sensorName + * @return time in millis + */ + public long getSensorRecordTime(String deviceId, String sensorName) throws DeviceControllerException { + DeviceRecord deviceRecord = deviceMap.get(deviceId); + if (deviceRecord != null) { + SensorRecord sensorRecord = deviceRecord.getSensorDataList().get(sensorName); + if (sensorRecord != null) { + return sensorRecord.getTime(); + } + throw new DeviceControllerException("Error: No records found for the Device ID: " + deviceId + + " Sensor Name: " + sensorName); + } + throw new DeviceControllerException("Error: No records found for the device ID: " + deviceId); + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorRecord.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorRecord.java new file mode 100644 index 000000000..88b9916fd --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/sensormgt/SensorRecord.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.sensormgt; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; + +@XmlRootElement +public class SensorRecord implements Serializable { + //sensor value float, int, boolean all should be converted into string + private String sensorValue; + private long time; + + public SensorRecord(String sensorValue, long time) { + this.sensorValue = sensorValue; + this.time = time; + } + + @XmlElement + public String getSensorValue() { + return sensorValue; + } + + @XmlElement + public long getTime() { + return time; + } + +} \ No newline at end of file diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/service/IoTServerStartupListener.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/service/IoTServerStartupListener.java new file mode 100644 index 000000000..22fd657cc --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/service/IoTServerStartupListener.java @@ -0,0 +1,41 @@ +/* + * 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.wso2.carbon.device.mgt.iot.service; + +import org.wso2.carbon.core.ServerStartupObserver; + +public class IoTServerStartupListener implements ServerStartupObserver { + private static volatile boolean serverReady = false; + @Override + public void completingServerStartup() { + } + + @Override + public void completedServerStartup() { + IoTServerStartupListener.setServerReady(true); + } + + public static boolean isServerReady() { + return IoTServerStartupListener.serverReady; + } + + public static void setServerReady(boolean serverReady) { + IoTServerStartupListener.serverReady = serverReady; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/CommunicationUtils.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/CommunicationUtils.java new file mode 100644 index 000000000..59cd7813d --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/CommunicationUtils.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.codec.binary.Base64; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; + +/** + * This is a utility class which contains methods common to the communication process of a client and the server. The + * methods include encryption/decryption of payloads and signing/verification of payloads received and to be sent. + */ +public class CommunicationUtils { + private static final Log log = LogFactory.getLog(TransportUtils.class); + // The Signature Algorithm used. + private static final String SIGNATURE_ALG = "SHA1withRSA"; + // The Encryption Algorithm and the Padding used. + private static final String CIPHER_PADDING = "RSA/ECB/PKCS1Padding"; + + /** + * Encrypts the message with the key that's passed in. + * + * @param message the message to be encrypted. + * @param encryptionKey the key to use for the encryption of the message. + * @return the encrypted message in String format. + * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding + * issues, encryption key being invalid or the algorithm used is unrecognizable. + */ + public static String encryptMessage(String message, Key encryptionKey) throws TransportHandlerException { + Cipher encrypter; + byte[] cipherData; + + try { + encrypter = Cipher.getInstance(CIPHER_PADDING); + encrypter.init(Cipher.ENCRYPT_MODE, encryptionKey); + cipherData = encrypter.doFinal(message.getBytes(StandardCharsets.UTF_8)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + encryptionKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return Base64.encodeBase64String(cipherData); + } + +///TODO:: Exception needs to change according to the common package + + /** + * Signed a given message using the PrivateKey that's passes in. + * + * @param message the message to be signed. Ideally some encrypted payload. + * @param signatureKey the PrivateKey with which the message is to be signed. + * @return the Base64Encoded String of the signed payload. + * @throws TransportHandlerException if some error occurs with the signing process which may be related to the + * signature algorithm used or the key used for signing. + */ + public static String signMessage(String message, PrivateKey signatureKey) throws TransportHandlerException { + + Signature signature; + String signedEncodedString; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initSign(signatureKey); + signature.update(Base64.decodeBase64(message)); + + byte[] signatureBytes = signature.sign(); + signedEncodedString = Base64.encodeBase64String(signatureBytes); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = + "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + signatureKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + return signedEncodedString; + } + + /** + * Verifies some signed-data against the a Public-Key to ensure that it was produced by the holder of the + * corresponding Private Key. + * + * @param data the actual payoad which was signed by some Private Key. + * @param signedData the signed data produced by signing the payload using a Private Key. + * @param verificationKey the corresponding Public Key which is an exact pair of the Private-Key with we expect + * the data to be signed by. + * @return true if the signed data verifies to be signed by the corresponding Private Key. + * @throws TransportHandlerException if some error occurs with the verification process which may be related to + * the signature algorithm used or the key used for signing. + */ + public static boolean verifySignature(String data, String signedData, PublicKey verificationKey) + throws TransportHandlerException { + + Signature signature; + boolean verified; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initVerify(verificationKey); + signature.update(Base64.decodeBase64(data)); + + verified = signature.verify(Base64.decodeBase64(signedData)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = + "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + verificationKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + return verified; + } + + /** + * Encrypts the message with the key that's passed in. + * + * @param encryptedMessage the encrypted message that is supposed to be decrypted. + * @param decryptKey the key to use in the decryption process. + * @return the decrypted message in String format. + * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding + * issues, encryption key being invalid or the algorithm used is unrecognizable. + */ + public static String decryptMessage(String encryptedMessage, Key decryptKey) throws TransportHandlerException { + + Cipher decrypter; + String decryptedMessage; + + try { + + decrypter = Cipher.getInstance(CIPHER_PADDING); + decrypter.init(Cipher.DECRYPT_MODE, decryptKey); + decryptedMessage = new String(decrypter.doFinal(Base64.decodeBase64(encryptedMessage)), + StandardCharsets.UTF_8); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + decryptKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + return decryptedMessage; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandler.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandler.java new file mode 100644 index 000000000..b81bdba4f --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandler.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.wso2.carbon.device.mgt.iot.transport; + +/** + * This interface consists of the core functionality related to the transport between any device and the server. The + * interface is an abstraction, regardless of the underlying protocol used for the transport. Implementation of this + * interface by any class that caters a specific protocol (ex: HTTP, XMPP, MQTT, CoAP) would ideally have methods + * specific to the protocol used for communication and other methods that implement the logic related to the devices + * using the protocol. The methods of the interface are identified as generic ones for implementing transport + * protocols for device communication. The implementation can utilize the appropriate method signatures applicable for + * intended protocol. + * + * @param an object of the message type specific to the protocol implemented. To be set to 'String' if there + * isn't anything specific. + */ +public interface TransportHandler { + // a default timeout interval to be used for the protocol specific connections + int DEFAULT_TIMEOUT_INTERVAL = 5000; // millis ~ 5 sec + + /** + * Implements the underlying connect mechanism specific to the protocol enabled by the interface. An object of a + * class that implements this interface would call this method before any communication is started via the + * intended protocol. + */ + void connect(); + + /** + * Used to check whether a connection (via the implemented protocol) to the external-endpoint exists. Ideally + * used to verify that the connection persists and to spawn a reconnection attempt if not. + * + * @return 'true' if connection is already made & exists, else 'false'. + */ + boolean isConnected(); + + /** + * @throws TransportHandlerException in the event of any exceptions that occur whilst processing the message. + * @see TransportHandler#processIncomingMessage(Object, String...) + */ + void processIncomingMessage() throws TransportHandlerException; + + /** + * @param message the message (of the type specific to the protocol) received from the device. + * @throws TransportHandlerException + * @see TransportHandler#processIncomingMessage(Object, String...) + */ + void processIncomingMessage(T message) throws TransportHandlerException; + + /** + * This is an overloaded method with three different method-signatures. This method is used to process any + * incoming messages via the implemented protocol. It would ideally be invoked at a point where a message + * received event is activated (Ex: `MessageArrived` callback in Eclipse-Paho-MQTT Client & `PacketListener`(s) + * in XMPP). + *

      + * + * @param message the message (of the type specific to the protocol) received from the device. + * @param messageParams one or more other parameters received as part-of & relevant-to the message (Ex: MQTT Topic). + * @throws TransportHandlerException in the event of any exceptions that occur whilst processing the message. + */ + void processIncomingMessage(T message, String... messageParams) throws TransportHandlerException; + + /** + * @throws TransportHandlerException in the event of any exceptions that occur whilst sending the message. + * @see TransportHandler#publishDeviceData(String...) + */ + void publishDeviceData() throws TransportHandlerException; + + /** + * @param publishData the message (of the type specific to the protocol) to be sent to the device. + * @throws TransportHandlerException in the event of any exceptions that occur whilst sending the message. + * @see TransportHandler#publishDeviceData(String...) + */ + void publishDeviceData(T publishData) throws TransportHandlerException; + + /** + * This is an overloaded method with three different method-signatures. This method is used to publish messages + * to an external-endpoint/device via the implemented protocol. It could in itself call the (communicating) + * external-endpoint or invoke any method provided by the protocol specific library. + *

      + * + * @param publishData one or more parameters specific to the message and the data to be sent. + * @throws TransportHandlerException in the event of any exceptions that occur whilst sending the message. + */ + void publishDeviceData(String... publishData) throws TransportHandlerException; + + /** + * Implements the underlying disconnect mechanism specific to the protocol enabled by the interface. An object of a + * class that implements this interface would call this method upon completion of all communication. In the case of + * the IoT-Server invoking this would only be required if the server shuts-down. + */ + void disconnect(); +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandlerException.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandlerException.java new file mode 100644 index 000000000..c862e56d8 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportHandlerException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.transport; + +public class TransportHandlerException extends Exception { + + private static final long serialVersionUID = 2736466230451105440L; + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public TransportHandlerException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public TransportHandlerException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public TransportHandlerException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public TransportHandlerException() { + super(); + } + + public TransportHandlerException(Throwable cause) { + super(cause); + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportUtils.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportUtils.java new file mode 100644 index 000000000..b6f32778b --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/TransportUtils.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.DatagramSocket; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.SocketException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class TransportUtils { + private static final Log log = LogFactory.getLog(TransportUtils.class); + + public static final int MIN_PORT_NUMBER = 9000; + public static final int MAX_PORT_NUMBER = 11000; + + /** + * Given a server endpoint as a String, this method splits it into Protocol, Host and Port + * + * @param ipString a network endpoint in the format - '://:' + * @return a map with keys "Protocol", "Host" & "Port" for the related values from the ipString + * @throws TransportHandlerException + */ + public static Map getHostAndPort(String ipString) + throws TransportHandlerException { + Map ipPortMap = new HashMap(); + String[] ipPortArray = ipString.split(":"); + + if (ipPortArray.length != 3) { + String errorMsg = + "The IP String - '" + ipString + + "' is invalid. It needs to be in format '://:'."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg); + } + + ipPortMap.put("Protocol", ipPortArray[0]); + ipPortMap.put("Host", ipPortArray[1].replace(File.separator, "")); + ipPortMap.put("Port", ipPortArray[2]); + return ipPortMap; + } + + /** + * This method validates whether a specific IP Address is of IPv4 type + * + * @param ipAddress the IP Address which needs to be validated + * @return true if it is of IPv4 type and false otherwise + */ + public static boolean validateIPv4(String ipAddress) { + try { + if (ipAddress == null || ipAddress.isEmpty()) { + return false; + } + + String[] parts = ipAddress.split("\\."); + if (parts.length != 4) { + return false; + } + + for (String s : parts) { + int i = Integer.parseInt(s); + if ((i < 0) || (i > 255)) { + return false; + } + } + return !ipAddress.endsWith("."); + + } catch (NumberFormatException nfe) { + log.warn("The IP Address: " + ipAddress + " could not " + + "be validated against IPv4-style"); + return false; + } + } + + public static Map getInterfaceIPMap() throws TransportHandlerException { + + Map interfaceToIPMap = new HashMap(); + Enumeration networkInterfaces; + String networkInterfaceName = ""; + String ipAddress; + + try { + networkInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException exception) { + String errorMsg = + "Error encountered whilst trying to get the list of network-interfaces"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + try { + for (; networkInterfaces.hasMoreElements(); ) { + networkInterfaceName = networkInterfaces.nextElement().getName(); + + if (log.isDebugEnabled()) { + log.debug("Network Interface: " + networkInterfaceName); + log.debug("------------------------------------------"); + } + + Enumeration interfaceIPAddresses = NetworkInterface.getByName( + networkInterfaceName).getInetAddresses(); + + for (; interfaceIPAddresses.hasMoreElements(); ) { + ipAddress = interfaceIPAddresses.nextElement().getHostAddress(); + + if (log.isDebugEnabled()) { + log.debug("IP Address: " + ipAddress); + } + + if (TransportUtils.validateIPv4(ipAddress)) { + interfaceToIPMap.put(networkInterfaceName, ipAddress); + } + } + + if (log.isDebugEnabled()) { + log.debug("------------------------------------------"); + } + } + } catch (SocketException exception) { + String errorMsg = + "Error encountered whilst trying to get the IP Addresses of the network " + + "interface: " + networkInterfaceName; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + return interfaceToIPMap; + } + + /** + * Attempts to find a free port between the MIN_PORT_NUMBER(9000) and MAX_PORT_NUMBER(11000). + * Tries 'RANDOMLY picked' port numbers between this range up-until "randomAttempts" number of + * times. If still fails, then tries each port in descending order from the MAX_PORT_NUMBER + * whilst skipping already attempted ones via random selection. + * + * @param randomAttempts no of times to TEST port numbers picked randomly over the given range + * @return an available/free port + */ + public static synchronized int getAvailablePort(int randomAttempts) { + ArrayList failedPorts = new ArrayList(randomAttempts); + + Random randomNum = new Random(); + int randomPort = MAX_PORT_NUMBER; + + while (randomAttempts > 0) { + randomPort = randomNum.nextInt(MAX_PORT_NUMBER - MIN_PORT_NUMBER) + MIN_PORT_NUMBER; + + if (checkIfPortAvailable(randomPort)) { + return randomPort; + } + failedPorts.add(randomPort); + randomAttempts--; + } + + randomPort = MAX_PORT_NUMBER; + + while (true) { + if (!failedPorts.contains(randomPort) && checkIfPortAvailable(randomPort)) { + return randomPort; + } + randomPort--; + } + } + + private static boolean checkIfPortAvailable(int port) { + ServerSocket tcpSocket = null; + DatagramSocket udpSocket = null; + + try { + tcpSocket = new ServerSocket(port); + tcpSocket.setReuseAddress(true); + + udpSocket = new DatagramSocket(port); + udpSocket.setReuseAddress(true); + return true; + } catch (IOException ex) { + // denotes the port is in use + } finally { + if (tcpSocket != null) { + try { + tcpSocket.close(); + } catch (IOException e) { + /* not to be thrown */ + } + } + + if (udpSocket != null) { + udpSocket.close(); + } + } + + return false; + } + + /** + * This is a utility method that creates and returns a HTTP connection object. + * + * @param urlString the URL pattern to which the connection needs to be created + * @return an HTTPConnection object which cn be used to send HTTP requests + * @throws TransportHandlerException if errors occur when creating the HTTP connection with + * the given URL string + */ + public static HttpURLConnection getHttpConnection(String urlString) throws + TransportHandlerException { + URL connectionUrl; + HttpURLConnection httpConnection; + + try { + connectionUrl = new URL(urlString); + httpConnection = (HttpURLConnection) connectionUrl.openConnection(); + } catch (MalformedURLException e) { + String errorMsg = "Error occured whilst trying to form HTTP-URL from string: " + urlString; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IOException exception) { + String errorMsg = "Error occured whilst trying to open a connection to: " + urlString; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + return httpConnection; + } + + /** + * This is a utility method that reads and returns the response from a HTTP connection + * + * @param httpConnection the connection from which a response is expected + * @return the response (as a string) from the given HTTP connection + * @throws TransportHandlerException if any errors occur whilst reading the response from + * the connection stream + */ + public static String readResponseFromHttpRequest(HttpURLConnection httpConnection) + throws TransportHandlerException { + BufferedReader bufferedReader; + try { + bufferedReader = new BufferedReader(new InputStreamReader( + httpConnection.getInputStream(), StandardCharsets.UTF_8)); + } catch (IOException exception) { + String errorMsg = "There is an issue with connecting the reader to the input stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + String responseLine; + StringBuilder completeResponse = new StringBuilder(); + + try { + while ((responseLine = bufferedReader.readLine()) != null) { + completeResponse.append(responseLine); + } + } catch (IOException exception) { + String errorMsg = "Error occured whilst trying read from the connection stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + try { + bufferedReader.close(); + } catch (IOException exception) { + log.error("Could not succesfully close the bufferedReader to the connection at: " + httpConnection.getURL()); + } + return completeResponse.toString(); + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/mqtt/MQTTTransportHandler.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/mqtt/MQTTTransportHandler.java new file mode 100644 index 000000000..a413bbf9c --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/mqtt/MQTTTransportHandler.java @@ -0,0 +1,402 @@ +/* + * 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.wso2.carbon.device.mgt.iot.transport.mqtt; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the MQTT-Transport specific implementations. The class implements utility methods for the + * case of a MQTT communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the MQTT specific functionality (ideally a device API writer who would like to communicate to the device + * via MQTT Protocol). + *

      + * This class contains the Device-Management specific implementation for all the MQTT functionality. This includes + * connecting to a MQTT Broker & subscribing to the appropriate MQTT-topic, action plan upon losing connection or + * successfully delivering a message to the broker and upon receiving a MQTT message. Makes use of the 'Paho-MQTT' + * library provided by Eclipse Org. + */ +public abstract class MQTTTransportHandler implements MqttCallback, TransportHandler { + + private static final Log log = LogFactory.getLog(MQTTTransportHandler.class); + private MqttClient client; + private String clientId; + private MqttConnectOptions options; // options to be set to the client-connection. + // topic to which a will-message is automatically published by the broker upon the device losing its connection. + private String clientWillTopic; + protected String mqttBrokerEndPoint; + protected int timeoutInterval; // interval to use for reconnection attempts etc. + protected String subscribeTopic; + // Quality of Service Levels for MQTT Subscription and Publishing. + public static final int QoS_0 = 0; // At-Most Once + @SuppressWarnings("unused") + public static final int QoS_1 = 1; // At-Least Once + public static final int QoS_2 = 2; // Exactly Once + public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = QoS_0; + // Prefix to the Will-Topic to which a message is published if client loses its connection. + private static final String DISCONNECTION_WILL_TOPIC_PREFIX = "Disconnection/"; + // Will-Message of the client to be published if connection is lost. + private static final String DISCONNECTION_WILL_MSG = "Lost-Connection"; + + /** + * Constructor for the MQTTTransportHandler which takes in the owner, type of the device and the MQTT Broker URL + * and the topic to subscribe. + * + * @param deviceOwner the owner of the device. + * @param deviceType the CDMF Device-Type of the device. + * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint. + * @param subscribeTopic the MQTT topic to which the client is to be subscribed. + */ + protected MQTTTransportHandler(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic) { + this.clientId = deviceOwner + ":" + deviceType; + this.subscribeTopic = subscribeTopic; + this.clientWillTopic = DISCONNECTION_WILL_TOPIC_PREFIX + deviceType; + this.mqttBrokerEndPoint = mqttBrokerEndPoint; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + this.initMQTTClient(); + } + + /** + * Constructor for the MQTTTransportHandler which takes in the owner, type of the device and the MQTT Broker URL + * and the topic to subscribe. Additionally this constructor takes in the reconnection-time interval between + * successive attempts to connect to the broker. + * + * @param deviceOwner the owner of the device. + * @param deviceType the CDMF Device-Type of the device. + * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint. + * @param subscribeTopic the MQTT topic to which the client is to be subscribed + * @param intervalInMillis the time interval in MILLI-SECONDS between attempts to connect to the broker. + */ + protected MQTTTransportHandler(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic, int intervalInMillis) { + this.clientId = deviceOwner + ":" + deviceType; + this.subscribeTopic = subscribeTopic; + this.clientWillTopic = DISCONNECTION_WILL_TOPIC_PREFIX + deviceType; + this.mqttBrokerEndPoint = mqttBrokerEndPoint; + this.timeoutInterval = intervalInMillis; + this.initMQTTClient(); + } + + /** + * Initializes the MQTT-Client. Creates a client using the given MQTT-broker endpoint and the clientId (which is + * constructed by a concatenation of [deviceOwner]:[deviceType]). Also sets the client's options parameter with + * the clientWillTopic (in-case of connection failure) and other info. Also sets the callback to this current class. + */ + private void initMQTTClient() { + try { + client = new MqttClient(this.mqttBrokerEndPoint, clientId, null); + log.info("MQTT client was created with ClientID : " + clientId); + } catch (MqttException ex) { + String errorMsg = "Initializing the MQTT Client failed."; + log.error(errorMsg, ex); + //TODO:: Throw the error out + } + options = new MqttConnectOptions(); + options.setKeepAliveInterval(120); // set the keep alive interval to 120 seconds by default. + options.setCleanSession(true); // sets clean session to true by default. + setDisconnectionWillForClient(QoS_2, true); // sets default will-topic & msg with QoS 2 and retained true. + client.setCallback(this); // callback for MQTT events are set to `this` object. + } + + /** + * @param qos the Quality of Service at which the last-will-message is to be published. + * @param isRetained indicate whether to retain the last-will-message. + * @see MQTTTransportHandler#setDisconnectionWillForClient(String, String, int, boolean). Uses the default values + * for Will-Topic and Will-Message. + */ + protected void setDisconnectionWillForClient(int qos, boolean isRetained) { + this.setDisconnectionWillForClient(clientWillTopic, DISCONNECTION_WILL_MSG, qos, isRetained); + } + + /** + * Sets the [Will] option in the default options-set of the MQTT Client. A will-topic, will-message is parsed + * along with the QoS and the retained flag. When the client loses its connection to the broker, the broker + * publishes the will-message to the will-topic, to itself. + * + * @param willTopic the topic to which the last will message is to be published when client exists ungracefully. + * @param willMsg the message to be published upon client's ungraceful exit from the broker. + * @param qos the Quality of Service at which the last-will-message is to be published. + * @param isRetained indicate whether to retain the last-will-message. + */ + protected void setDisconnectionWillForClient(String willTopic, String willMsg, int qos, boolean isRetained) { + this.options.setWill(willTopic, willMsg.getBytes(StandardCharsets.UTF_8), qos, isRetained); + } + + /** + * Sets the [Clean-Session] option in the default options-set of the MQTT Client. It is set to `true` by default. + * + * @param setCleanSession `true` indicates that the session details can be cleared/cleaned upon disconnection, + * `false` indicates that the session details are to be persisted if the client disconnects. + */ + @SuppressWarnings("unused") + protected void setClientCleanSession(boolean setCleanSession) { + this.options.setCleanSession(setCleanSession); + } + + /** + * Sets the [Username] & [Password] options in the default options-set of the MQTT Client. By default these + * values are not set. + * + * @param username the username to be used by the client to connect to the broker. + * @param password the password to be used by the client to connect to the broker. + */ + @SuppressWarnings("unused") + protected void setUsernameAndPassword(String username, String password) { + this.options.setUserName(username); + this.options.setPassword(password.toCharArray()); + } + + /** + * Connects to the MQTT-Broker at the endpoint specified in the constructor to this class using default the + * MQTT-options. + * + * @throws TransportHandlerException in the event of 'Connecting to' the MQTT broker fails. + */ + protected void connectToQueue() throws TransportHandlerException { + this.connectToQueue(options); + } + + /** + * Connects to the MQTT-Broker at the endpoint specified in the constructor to this class using the MQTT-Options + * passed. + * + * @param options options to be used by the client for this connection. (username, password, clean-session, etc) + * @throws TransportHandlerException in the event of 'Connecting to' the MQTT broker fails. + */ + protected void connectToQueue(MqttConnectOptions options) throws TransportHandlerException { + try { + client.connect(options); + if (log.isDebugEnabled()) { + log.debug("MQTT Client connected to queue at: " + this.mqttBrokerEndPoint); + } + } catch (MqttException ex) { + String errorMsg = "MQTT Exception occured whilst connecting to queue at [" + this.mqttBrokerEndPoint + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + /** + * @throws TransportHandlerException in the event of 'Subscribing to' the MQTT broker fails. + * @see MQTTTransportHandler#subscribeToQueue(int). Uses default QoS of 1. + */ + protected void subscribeToQueue() throws TransportHandlerException { + this.subscribeToQueue(QoS_0); + } + + /** + * Subscribes to the MQTT-Topic specified in the constructor to this class. + * + * @throws TransportHandlerException in the event of 'Subscribing to' the MQTT broker fails. + */ + protected void subscribeToQueue(int qos) throws TransportHandlerException { + try { + client.subscribe(subscribeTopic, qos); + if (log.isDebugEnabled()) { + log.debug("Client [" + clientId + "] subscribed to topic: " + subscribeTopic); + } + } catch (MqttException ex) { + String errorMsg = "MQTT Exception occurred whilst client [" + clientId + "] tried to subscribe to " + + "topic: [" + subscribeTopic + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + /** + * @param topic the topic to which the message is to be published. + * @param payLoad the message (payload) of the MQTT publish action. + * @see MQTTTransportHandler#publishToQueue(String, String, int, boolean) + */ + @SuppressWarnings("unused") + protected void publishToQueue(String topic, String payLoad) throws TransportHandlerException { + publishToQueue(topic, payLoad, DEFAULT_MQTT_QUALITY_OF_SERVICE, false); + } + + /** + * @param topic the topic to which the message is to be published. + * @param message the message (payload) of the MQTT publish action as a `MQTTMessage`. + * @throws TransportHandlerException if any error occurs whilst trying to publish to the MQTT Queue. + * @see MQTTTransportHandler#publishToQueue(String, String, int, boolean) + */ + protected void publishToQueue(String topic, MqttMessage message) throws TransportHandlerException { + try { + client.publish(topic, message); + if (log.isDebugEnabled()) { + log.debug("Message: " + message.toString() + " to MQTT topic [" + topic + "] published successfully"); + } + } catch (MqttException ex) { + String errorMsg = "MQTT Client Error whilst client [" + clientId + "] tried to publish to queue at " + + "[" + mqttBrokerEndPoint + "] under topic [" + topic + "]"; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + /** + * This method is used to publish messages to the MQTT-Endpoint to which this client is connected to. It is via + * publishing to this broker that the messages are communicated to the device. This is an overloaded method with + * different parameter combinations. This method invokes the publish method provided by the MQTT-Client library. + * + * @param topic the topic to which the message is to be published. + * @param payLoad the message (payload) of the MQTT publish action. + * @param qos the Quality-of-Service of the current publish action. + * Could be 0(At-most once), 1(At-least once) or 2(Exactly once) + * @param retained indicate whether to retain the publish-message in the event of no subscribers. + * @throws TransportHandlerException if any error occurs whilst trying to publish to the MQTT Queue. + */ + protected void publishToQueue(String topic, String payLoad, int qos, boolean retained) + throws TransportHandlerException { + try { + client.publish(topic, payLoad.getBytes(StandardCharsets.UTF_8), qos, retained); + if (log.isDebugEnabled()) { + log.debug("Message: " + payLoad + " to MQTT topic [" + topic + "] published successfully"); + } + } catch (MqttException ex) { + String errorMsg = "MQTT Client Error whilst client [" + clientId + "] tried to publish to queue at " + + "[" + mqttBrokerEndPoint + "] under topic [" + topic + "]"; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + /** + * Checks whether the connection to the MQTT-Broker exists. + * + * @return `true` if the client is connected to the MQTT-Broker, else `false`. + */ + @Override + public boolean isConnected() { + return client.isConnected(); + } + + /** + * Callback method which is triggered once the MQTT client losers its connection to the broker. Spawns a new + * thread that executes necessary actions to try and reconnect to the endpoint. + * + * @param throwable a Throwable Object containing the details as to why the failure occurred. + */ + @Override + public void connectionLost(Throwable throwable) { + if (log.isDebugEnabled()) { + log.warn("Connection for client: " + this.clientId + " to " + this.mqttBrokerEndPoint + " was lost." + + "\nThis was due to - " + throwable.getMessage()); + } + + Thread reconnectThread = new Thread() { + public void run() { + connect(); + } + }; + reconnectThread.setDaemon(true); + reconnectThread.start(); + } + + /** + * Callback method which is triggered upon receiving a MQTT Message from the broker. Spawns a new thread that + * executes any actions to be taken with the received message. + * + * @param topic the MQTT-Topic to which the received message was published to and the client subscribed to. + * @param mqttMessage the actual MQTT-Message that was received from the broker. + */ + @Override + public void messageArrived(final String topic, final MqttMessage mqttMessage) { + if (log.isDebugEnabled()) { + log.debug("Got an MQTT message '" + mqttMessage.toString() + "' for topic '" + topic + "'."); + } + + Thread messageProcessorThread = new Thread() { + public void run() { + try { + processIncomingMessage(mqttMessage, topic); + } catch (TransportHandlerException e) { + log.error("An error occurred when trying to process received MQTT message [" + mqttMessage + "] " + + "for topic [" + topic + "].", e); + } + } + }; + messageProcessorThread.setDaemon(true); + messageProcessorThread.start(); + } + + /** + * Callback method which gets triggered upon successful completion of a message delivery to the broker. + * + * @param iMqttDeliveryToken the MQTT-DeliveryToken which includes the details about the specific message delivery. + */ + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + String topic = iMqttDeliveryToken.getTopics()[0]; + String client = iMqttDeliveryToken.getClient().getClientId(); + + try { + if (iMqttDeliveryToken.isComplete()) { + if (log.isDebugEnabled()) { + if (iMqttDeliveryToken.getMessage() != null) { + String message = iMqttDeliveryToken.getMessage().toString(); + log.debug("Message to client [" + client + "] under topic (" + topic + + ") was delivered successfully with the delivery message: '" + message + "'"); + } else { + log.debug("Message to client [" + client + "] under topic (" + topic + + ") was delivered successfully."); + } + } + } else { + log.warn("FAILED: Delivery of MQTT message to [" + client + "] under topic [" + topic + "] failed."); + } + } catch (MqttException e) { + log.warn("Error occurred whilst trying to read the message from the MQTT delivery token."); + } + } + + /** + * Closes the connection to the MQTT Broker. + */ + public void closeConnection() throws MqttException { + if (client != null && isConnected()) { + client.disconnect(); + } + } + + /** + * Fetches the default options set for the MQTT Client + * + * @return the options that are currently set for the client. + */ + public MqttConnectOptions getOptions() { + return options; + } +} + diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/xmpp/XMPPTransportHandler.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/xmpp/XMPPTransportHandler.java new file mode 100644 index 000000000..1c57897f8 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/transport/xmpp/XMPPTransportHandler.java @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.transport.xmpp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.ConnectionConfiguration; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.AndFilter; +import org.jivesoftware.smack.filter.FromContainsFilter; +import org.jivesoftware.smack.filter.OrFilter; +import org.jivesoftware.smack.filter.PacketFilter; +import org.jivesoftware.smack.filter.PacketTypeFilter; +import org.jivesoftware.smack.filter.ToContainsFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + *

      + * This class contains the IoT-Server specific implementation for all the XMPP functionality. This includes + * connecting to a XMPP Server & Login-In using the device's/server's XMPP-Account, Setting listeners and filters on + * incoming XMPP messages and Sending XMPP replies for messages received. Makes use of the 'Smack-XMPP' library + * provided by jivesoftware/igniterealtime. + */ +public abstract class XMPPTransportHandler implements TransportHandler { + + private static final Log log = LogFactory.getLog(XMPPTransportHandler.class); + protected String server; + protected int timeoutInterval; // millis + //TODO:: Shouldnt be hard-coded. Need to be read from configs + private static final int DEFAULT_XMPP_PORT = 5222; + private XMPPConnection connection; + private int port; + private PacketFilter filter; + private PacketListener listener; + + /** + * Constructor for XMPPTransportHandler passing only the server-IP. + * + * @param server the IP of the XMPP server. + */ + @SuppressWarnings("unused") + protected XMPPTransportHandler(String server) { + this.server = server; + this.port = DEFAULT_XMPP_PORT; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + initXMPPClient(); + } + + /** + * Constructor for XMPPTransportHandler passing server-IP and the XMPP-port. + * + * @param server the IP of the XMPP server. + * @param port the XMPP server's port to connect to. (default - 5222) + */ + protected XMPPTransportHandler(String server, int port) { + this.server = server; + this.port = port; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + initXMPPClient(); + } + + /** + * Constructor for XMPPTransportHandler passing server-IP, the XMPP-port and the + * timeoutInterval used by listeners to the server and for reconnection schedules. + * + * @param server the IP of the XMPP server. + * @param port the XMPP server's port to connect to. (default - 5222) + * @param timeoutInterval the timeout interval to use for the connection and reconnection + */ + @SuppressWarnings("unused") + protected XMPPTransportHandler(String server, int port, int timeoutInterval) { + this.server = server; + this.port = port; + this.timeoutInterval = timeoutInterval; + initXMPPClient(); + } + + /** + * Sets the client's time-out-limit whilst waiting for XMPP-replies from server. + * + * @param millis the time in millis to be set as the time-out-limit whilst waiting for a + * XMPP-reply. + */ + @SuppressWarnings("unused") + public void setTimeoutInterval(int millis) { + this.timeoutInterval = millis; + } + + /** + * Checks whether the connection to the XMPP-Server persists. + * + * @return true if the client is connected to the XMPP-Server, else false. + */ + @Override + public boolean isConnected() { + return connection.isConnected(); + } + + /** + * Initializes the XMPP Client. Sets the time-out-limit whilst waiting for XMPP-replies from + * server. Sets the XMPP configurations to connect to the server and creates the + * XMPPConnection object used for connecting and Logging-In. + */ + private void initXMPPClient() { + log.info(String.format("Initializing connection to XMPP Server at %1$s via port " + + "%2$d.", server, port)); + SmackConfiguration.setPacketReplyTimeout(timeoutInterval); + ConnectionConfiguration config = new ConnectionConfiguration(server, port); +// TODO:: Need to enable SASL-Authentication appropriately + config.setSASLAuthenticationEnabled(false); + config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled); + connection = new XMPPConnection(config); + } + +//TODO:: Re-check all exception handling + + /** + * Connects to the XMPP-Server and if attempt unsuccessful, then throws exception. + * + * @throws TransportHandlerException in the event of 'Connecting to' the XMPP server fails. + */ + protected void connectToServer() throws TransportHandlerException { + try { + connection.connect(); + log.info(String.format( + "Connection to XMPP Server at %1$s established successfully......", server)); + + } catch (XMPPException xmppExcepion) { + String errorMsg = + "Connection attempt to the XMPP Server at " + server + " via port " + port + + " failed."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, xmppExcepion); + } + } + + /** + * If successfully established connection, then tries to Log in using the device's XMPP + * Account credentials. + * + * @param username the username of the device's XMPP-Account. + * @param password the password of the device's XMPP-Account. + * @param resource the resource the resource, specific to the XMPP-Account to which the login + * is made to + * @throws TransportHandlerException in the event of 'Logging into' the XMPP server fails. + */ + protected void loginToServer(String username, String password, String resource) + throws TransportHandlerException { + if (isConnected()) { + try { + if (resource == null) { + connection.login(username, password); + log.info(String.format("Logged into XMPP Server at %1$s as user %2$s......", + server, username)); + } else { + connection.login(username, password, resource); + log.info(String.format( + "Logged into XMPP Server at %1$s as user %2$s on resource %3$s......", + server, username, resource)); + } + } catch (XMPPException xmppException) { + String errorMsg = + "Login attempt to the XMPP Server at " + server + " with username - " + + username + " failed."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, xmppException); + } + } else {//TODO:: Log not required + String errorMsg = + "Not connected to XMPP-Server to attempt Login. Please 'connectToServer' " + + "before Login"; + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + throw new TransportHandlerException(errorMsg); + } + } + + /** + * Sets a filter for all the incoming XMPP-Messages on the Sender's JID (XMPP-Account ID). + * Also creates a listener for the incoming messages and connects the listener to the + * XMPPConnection alongside the set filter. + * + * @param senderJID the JID (XMPP-Account ID of the sender) to which the filter is to be set. + */ + @SuppressWarnings("unused") + protected void setFilterOnSender(String senderJID) { + filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter( + senderJID)); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + try { + processIncomingMessage(xmppMessage); + } catch (TransportHandlerException e) { + log.error("An error occurred when trying to process received XMPP message " + + "[" + xmppMessage.getBody() + "].", e); + } + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + connection.addPacketListener(listener, filter); + } + + /** + * Sets a filter for all the incoming XMPP-Messages on the Receiver's JID (XMPP-Account ID). + * Also creates a listener for the incoming messages and connects the listener to the + * XMPPConnection alongside the set filter. + * + * @param receiverJID the JID (XMPP-Account ID of the receiver) to which the filter is to be + * set. + */ + protected void setFilterOnReceiver(String receiverJID) { + filter = new AndFilter(new PacketTypeFilter(Message.class), new ToContainsFilter( + receiverJID)); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + try { + processIncomingMessage(xmppMessage); + } catch (TransportHandlerException e) { + log.error("An error occurred when trying to process received XMPP message " + + "[" + xmppMessage.getBody() + "].", e); + } + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + connection.addPacketListener(listener, filter); + } + + /** + * Sets a filter for all the incoming XMPP-Messages on the From-JID & To-JID (XMPP-Account IDs) + * passed in. Also creates a listener for the incoming messages and connects the listener to + * the XMPPConnection alongside the set filter. + * + * @param senderJID the From-JID (XMPP-Account ID) to which the filter is to be set. + * @param receiverJID the To-JID (XMPP-Account ID) to which the filter is to be set. + * @param andCondition if true: then filter is set with 'AND' operator (senderJID && + * receiverJID), + * if false: then the filter is set with 'OR' operator (senderJID | + * receiverJID) + */ + @SuppressWarnings("unused") + protected void setMessageFilterAndListener(String senderJID, String receiverJID, boolean + andCondition) { + PacketFilter jidFilter; + + if (andCondition) { + jidFilter = new AndFilter(new FromContainsFilter(senderJID), new ToContainsFilter( + receiverJID)); + } else { + jidFilter = new OrFilter(new FromContainsFilter(senderJID), new ToContainsFilter( + receiverJID)); + } + + filter = new AndFilter(new PacketTypeFilter(Message.class), jidFilter); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + try { + processIncomingMessage(xmppMessage); + } catch (TransportHandlerException e) { + log.error("An error occurred when trying to process received XMPP message " + + "[" + xmppMessage.getBody() + "].", e); + } + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + connection.addPacketListener(listener, filter); + } + + /** + * Sends an XMPP message. Calls the overloaded method with Subject set to "Reply-From-Device" + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param message the XMPP-Message that is to be sent. + */ + @SuppressWarnings("unused") + protected void sendXMPPMessage(String JID, String message) { + sendXMPPMessage(JID, message, "XMPP-Message"); + } + + /** + * Overloaded method to send an XMPP message. Includes the subject to be mentioned in the + * message that is sent. + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param message the XMPP-Message that is to be sent. + * @param subject the subject that the XMPP-Message would carry. + */ + protected void sendXMPPMessage(String JID, String message, String subject) { + Message xmppMessage = new Message(); + xmppMessage.setTo(JID); + xmppMessage.setSubject(subject); + xmppMessage.setBody(message); + xmppMessage.setType(Message.Type.chat); + sendXMPPMessage(JID, xmppMessage); + } + + /** + * Sends an XMPP message. + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param xmppMessage the XMPP-Message that is to be sent. + */ + protected void sendXMPPMessage(String JID, Message xmppMessage) { + connection.sendPacket(xmppMessage); + if (log.isDebugEnabled()) { + log.debug("Message: '" + xmppMessage.getBody() + "' sent to XMPP JID [" + JID + "] sent successfully."); + } + } + + /** + * Closes the connection to the XMPP Server. + */ + public void closeConnection() { + if (connection != null && isConnected()) { + connection.disconnect(); + } + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IoTUtil.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IoTUtil.java new file mode 100644 index 000000000..76e375e27 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IoTUtil.java @@ -0,0 +1,127 @@ +/* + * 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.wso2.carbon.device.mgt.iot.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.PoolingClientConnectionManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.util.EntityUtils; +import org.wso2.carbon.base.ServerConfiguration; +import org.wso2.carbon.device.mgt.iot.exception.IoTException; +import org.wso2.carbon.device.mgt.iot.internal.IoTCommonDataHolder; +import org.wso2.carbon.utils.NetworkUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.SocketException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; + +public class IoTUtil { + + public static final String HOST_NAME = "HostName"; + private static final Log log = LogFactory.getLog(IoTUtil.class); + + /** + * Return a http client instance + * + * @param port - server port + * @param protocol- service endpoint protocol http/https + * @return + */ + public static HttpClient getHttpClient(int port, String protocol) + throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException { + SchemeRegistry registry = new SchemeRegistry(); + + if ("https".equals(protocol)) { + System.setProperty("javax.net.ssl.trustStrore", IoTCommonDataHolder.getInstance().getTrustStoreLocation()); + System.setProperty("javax.net.ssl.trustStorePassword", + IoTCommonDataHolder.getInstance().getTrustStorePassword()); + + if (port >= 0) { + registry.register(new Scheme("https", port, SSLSocketFactory.getSocketFactory())); + } else { + registry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); + } + } else if ("http".equals(protocol)) { + if (port >= 0) { + registry.register(new Scheme("http", port, PlainSocketFactory.getSocketFactory())); + } else { + registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory())); + } + } + HttpParams params = new BasicHttpParams(); + PoolingClientConnectionManager tcm = new PoolingClientConnectionManager(registry); + HttpClient client = new DefaultHttpClient(tcm, params); + return client; + } + + public static String getResponseString(HttpResponse httpResponse) throws IoTException { + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); + String readLine; + String response = ""; + while (((readLine = br.readLine()) != null)) { + response += readLine; + } + return response; + } catch (IOException e) { + throw new IoTException("Error while reading the response from the remote. " + + e.getMessage(), e); + } finally { + EntityUtils.consumeQuietly(httpResponse.getEntity()); + if (br != null) { + try { + br.close(); + } catch (IOException e) { + log.warn("Error while closing the connection! " + e.getMessage()); + } + } + } + } + + public static String getHostName() throws IoTException { + String hostName = ServerConfiguration.getInstance().getFirstProperty(HOST_NAME); + + try { + if (hostName == null) { + hostName = NetworkUtils.getLocalHostname(); + } + } catch (SocketException e) { + throw new IoTException("Error while trying to read hostname.", e); + } + + return hostName; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IotDeviceManagementUtil.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IotDeviceManagementUtil.java new file mode 100644 index 000000000..f1d14ff76 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/IotDeviceManagementUtil.java @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.util; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.utils.CarbonUtils; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * Provides utility methods required by the iot device management bundle. + */ +public class IotDeviceManagementUtil { + + private static final Log log = LogFactory.getLog(IotDeviceManagementUtil.class.getName()); + + public static Document convertToDocument(File file) throws DeviceManagementException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + DocumentBuilder docBuilder = factory.newDocumentBuilder(); + return docBuilder.parse(file); + } catch (Exception e) { + throw new DeviceManagementException("Error occurred while parsing file, while converting " + + "to a org.w3c.dom.Document : " + e.getMessage(), e); + } + } + + private 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 ZipArchive getSketchArchive(String archivesPath, String templateSketchPath, Map contextParams) + throws DeviceManagementException, IOException { + + String sep = File.separator; + String sketchPath = CarbonUtils.getCarbonHome() + sep + templateSketchPath; + + FileUtils.deleteDirectory(new File(archivesPath));//clear directory + FileUtils.deleteDirectory(new File(archivesPath + ".zip"));//clear zip + if (!new File(archivesPath).mkdirs()) { //new dir + String message = "Could not create directory at path: " + archivesPath; + log.error(message); + throw new DeviceManagementException(message); + } + + String zipFileName = "zipFile.zip"; + + try { + Map> properties = getProperties(sketchPath + sep + "sketch" + ".properties"); + List templateFiles = properties.get("templates"); + +// zipFileName = properties.get("zipfilename").get(0); + zipFileName = contextParams.get("DEVICE_NAME") + ".zip"; + + for (String templateFile : templateFiles) { + parseTemplate(templateSketchPath + sep + templateFile, archivesPath + sep + templateFile, + contextParams); + } + + templateFiles.add("sketch.properties"); // ommit copying the props file + copyFolder(new File(sketchPath), new File(archivesPath), templateFiles); + + } catch (IOException ex) { + throw new DeviceManagementException( + "Error occurred when trying to read property " + "file sketch.properties", ex); + } + + try { + createZipArchive(archivesPath); + } catch (IOException e) { + String message = "Zip file for the specific device agent not found at path: " + archivesPath; + log.error(message); + log.error(e); + throw new DeviceManagementException(message, e); + } + FileUtils.deleteDirectory(new File(archivesPath));//clear folder + + /* now get the zip file */ + File zip = new File(archivesPath + ".zip"); + return new ZipArchive(zipFileName, zip); + } + + private static Map> getProperties(String propertyFilePath) throws IOException { + Properties prop = new Properties(); + InputStream input = null; + + try { + + input = new FileInputStream(propertyFilePath); + + // load a properties file + prop.load(input); + Map> properties = new HashMap>(); + + String templates = prop.getProperty("templates"); + List list = new ArrayList(Arrays.asList(templates.split(","))); + properties.put("templates", list); + + final String filename = prop.getProperty("zipfilename"); + list = new ArrayList() {{ + add(filename); + }}; + properties.put("zipfilename", list); + return properties; + + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + private static void parseTemplate(String srcFile, String dstFile, Map contextParams) throws IOException { + //TODO add velocity 1.7, currently commented + //TODO conflicting when calling in CXF environment with the opensaml orbit + + // /* create a context and add data */ + // VelocityContext context = new VelocityContext(contextParams); + // + // /* first, get and initialize an engine */ + // VelocityEngine ve = new VelocityEngine(); + // ve.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, + // "org.apache.velocity.runtime.log.Log4JLogChute" ); + // ve.setProperty("runtime.log.logsystem.log4j.logger", IotDeviceManagementUtil.class.getName()); + // ve.init(); + // + // String sep = File.separator; + // Template t = ve.getTemplate(srcFile); + // FileWriter writer = null; + // try { + // writer = new FileWriter(dstFile); + // t.merge(context, writer); + // } finally { + // if (writer != null) { + // writer.flush(); + // writer.close(); + // } + // } + + //read from file + FileInputStream inputStream = new FileInputStream(srcFile); + String content = IOUtils.toString(inputStream, StandardCharsets.UTF_8.toString()); + Iterator iterator = contextParams.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry mapEntry = (Map.Entry) iterator.next(); + content = content.replaceAll("\\$\\{" + mapEntry.getKey() + "\\}", mapEntry.getValue().toString()); + } + if (inputStream != null) { + inputStream.close(); + } + //write to file + FileOutputStream outputStream = new FileOutputStream(dstFile); + IOUtils.write(content, outputStream, StandardCharsets.UTF_8.toString()); + if (outputStream != null) { + outputStream.close(); + } + } + + private static void copyFolder(File src, File dest, List excludeFileNames) throws IOException { + + if (src.isDirectory()) { + + //if directory not exists, create it + if (!dest.exists() && !dest.mkdirs()) { + String message = "Could not create directory at path: " + dest; + log.error(message); + throw new IOException(message); + } + + //list all the directory contents + String files[] = src.list(); + + if (files == null) { + log.warn("There are no files insides the directory " + src.getAbsolutePath()); + return; + } + + for (String file : files) { + //construct the src and dest file structure + File srcFile = new File(src, file); + File destFile = new File(dest, file); + //recursive copy + copyFolder(srcFile, destFile, excludeFileNames); + } + + } else { + for (String fileName : excludeFileNames) { + if (src.getName().equals(fileName)) { + return; + } + } + //if file, then copy it + //Use bytes stream to support all file types + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(src); + out = new FileOutputStream(dest); + + byte[] buffer = new byte[1024]; + + int length; + //copy the file content in bytes + while ((length = in.read(buffer)) > 0) { + out.write(buffer, 0, length); + } + } finally { + silentClose(in); + silentClose(out); + } + } + } + + private static void silentClose(InputStream is) { + if (is == null) { + return; + } + + try { + is.close(); + } catch (IOException e) { + // do nothing + } + + } + + private static void silentClose(OutputStream os) { + if (os == null) { + return; + } + + try { + + os.close(); + } catch (IOException e) { + // do nothing + } + } + + private static boolean createZipArchive(String srcFolder) throws IOException { + BufferedInputStream origin = null; + ZipOutputStream out = null; + + try { + final int BUFFER = 2048; + + FileOutputStream dest = new FileOutputStream(new File(srcFolder + ".zip")); + + out = new ZipOutputStream(new BufferedOutputStream(dest)); + byte data[] = new byte[BUFFER]; + + File subDir = new File(srcFolder); + String subdirList[] = subDir.list(); + + if (subdirList == null) { + log.warn("The sub directory " + subDir.getAbsolutePath() + " is empty"); + return false; + } + + for (String sd : subdirList) { + // get a list of files from current directory + File f = new File(srcFolder + "/" + sd); + if (f.isDirectory()) { + String files[] = f.list(); + + if (files == null) { + log.warn("The current directory " + f.getAbsolutePath() + " is empty. Has no files"); + return false; + } + + for (int i = 0; i < files.length; i++) { + FileInputStream fi = new FileInputStream(srcFolder + "/" + sd + "/" + files[i]); + origin = new BufferedInputStream(fi, BUFFER); + ZipEntry entry = new ZipEntry(sd + "/" + files[i]); + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + out.flush(); + } + + } + } else //it is just a file + { + FileInputStream fi = new FileInputStream(f); + origin = new BufferedInputStream(fi, BUFFER); + ZipEntry entry = new ZipEntry(sd); + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + out.flush(); + } + + } + } + + out.flush(); + } finally { + silentClose(origin); + silentClose(out); + } + return true; + } + +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipArchive.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipArchive.java new file mode 100644 index 000000000..b9720d112 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipArchive.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.util; + +import java.io.File; + +public class ZipArchive { + + private File zipFile = null; + private String fileName = null; + private String deviceId = null; + + public ZipArchive(String fileName, File zipFile) { + this.fileName = fileName; + this.zipFile = zipFile; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public File getZipFile() { + return zipFile; + } + + public String getFileName() { + return fileName; + } +} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipUtil.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipUtil.java new file mode 100644 index 000000000..8ea3396d6 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/src/main/java/org/wso2/carbon/device/mgt/iot/util/ZipUtil.java @@ -0,0 +1,100 @@ +/* + * 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.wso2.carbon.device.mgt.iot.util; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.exception.IoTException; +import org.wso2.carbon.utils.CarbonUtils; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class ZipUtil { + + private static final String HTTPS_PORT_PROPERTY = "httpsPort"; + private static final String HTTP_PORT_PROPERTY = "httpPort"; + + private static final String LOCALHOST = "localhost"; + private static final String HTTPS_PROTOCOL_APPENDER = "https://"; + private static final String HTTP_PROTOCOL_APPENDER = "http://"; + + public ZipArchive createZipFile(String owner, String tenantDomain, String deviceType, + String deviceId, String deviceName, String token, + String refreshToken) + throws DeviceManagementException { + + String sep = File.separator; + String sketchFolder = "repository" + sep + "resources" + sep + "sketches"; + String archivesPath = CarbonUtils.getCarbonHome() + sep + sketchFolder + sep + "archives" + sep + deviceId; + String templateSketchPath = sketchFolder + sep + deviceType; + String iotServerIP; + + try { + iotServerIP = IoTUtil.getHostName(); + } catch (IoTException e) { + throw new DeviceManagementException(e.getMessage()); + } + String httpsServerPort = System.getProperty(HTTPS_PORT_PROPERTY); + String httpServerPort = System.getProperty(HTTP_PORT_PROPERTY); + + String httpsServerEP = HTTPS_PROTOCOL_APPENDER + iotServerIP + ":" + httpsServerPort; + String httpServerEP = HTTP_PROTOCOL_APPENDER + iotServerIP + ":" + httpServerPort; + String apimEndpoint = httpsServerEP; + String mqttEndpoint = MqttConfig.getInstance().getMqttQueueEndpoint(); + if (mqttEndpoint.contains(LOCALHOST)) { + mqttEndpoint = mqttEndpoint.replace(LOCALHOST, iotServerIP); + } + + String xmppEndpoint = XmppConfig.getInstance().getXmppEndpoint(); + + int indexOfChar = xmppEndpoint.lastIndexOf(":"); + if (indexOfChar != -1) { + xmppEndpoint = xmppEndpoint.substring(0, indexOfChar); + } + + xmppEndpoint = xmppEndpoint + ":" + XmppConfig.getInstance().getSERVER_CONNECTION_PORT(); + + Map contextParams = new HashMap<>(); + //TODO:refactor remove and move to device type impl + contextParams.put("SERVER_NAME", "wso2"); + contextParams.put("DEVICE_OWNER", owner); + contextParams.put("DEVICE_ID", deviceId); + contextParams.put("DEVICE_NAME", deviceName); + contextParams.put("HTTPS_EP", httpsServerEP); + contextParams.put("HTTP_EP", httpServerEP); + contextParams.put("APIM_EP", apimEndpoint); + contextParams.put("MQTT_EP", mqttEndpoint); + contextParams.put("XMPP_EP", xmppEndpoint); + contextParams.put("DEVICE_TOKEN", token); + contextParams.put("DEVICE_REFRESH_TOKEN", refreshToken); + + ZipArchive zipFile; + try { + zipFile = IotDeviceManagementUtil.getSketchArchive(archivesPath, templateSketchPath, contextParams); + } catch (IOException e) { + throw new DeviceManagementException("Zip File Creation Failed", e); + } + + return zipFile; + } +} diff --git a/components/iot-plugins/iot-base-plugin/pom.xml b/components/iot-plugins/iot-base-plugin/pom.xml new file mode 100644 index 000000000..759eb4077 --- /dev/null +++ b/components/iot-plugins/iot-base-plugin/pom.xml @@ -0,0 +1,60 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + iot-base-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot + org.wso2.carbon.device.mgt.iot.api + org.wso2.carbon.device.mgt.iot.ui + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/iot-plugins/pom.xml b/components/iot-plugins/pom.xml new file mode 100644 index 000000000..0020ee7f1 --- /dev/null +++ b/components/iot-plugins/pom.xml @@ -0,0 +1,67 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + carbon-device-mgt-plugins-parent + 2.1.0-SNAPSHOT + ../../pom.xml + + + 4.0.0 + org.wso2.carbon.devicemgt-plugins + iot-plugins + pom + WSO2 Carbon - IoT Plugins + http://wso2.org + + + androidsense-plugin + arduino-plugin + camera-plugin + digital-display-plugin + drone-analyzer-plugin + raspberrypi-plugin + virtual-fire-alarm-plugin + iot-base-plugin + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/build.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/build.xml new file mode 100644 index 000000000..a877b1141 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/build.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/pom.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/pom.xml new file mode 100644 index 000000000..cfe0fb2a2 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/pom.xml @@ -0,0 +1,92 @@ + + + + + + + + raspberrypi-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.raspberrypi.analytics + WSO2 Carbon - IoT Server RaspberryPi Analytics capp + pom + + + + + maven-clean-plugin + 2.4.1 + + + auto-clean + initialize + + clean + + + + + + maven-antrun-plugin + 1.7 + + + process-resources + + + + + + + run + + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/assembly/src.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/assembly/src.xml new file mode 100644 index 000000000..a5a375010 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.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/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml new file mode 100644 index 000000000..28b710c27 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..25df56734 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_temperature.xml + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..ccfb3b314 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_temperature.xml + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml new file mode 100644 index 000000000..d06f73b14 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.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/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..27ec69702 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.temperature_1.0.0.json + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.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 000000000..5d94b9821 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json @@ -0,0 +1,20 @@ +{ + "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/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml new file mode 100644 index 000000000..41938dd4f --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..9b4228e30 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Temperature_Sensor_Script.xml + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml new file mode 100644 index 000000000..c4580f909 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/pom.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/pom.xml new file mode 100644 index 000000000..4173e23e1 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/pom.xml @@ -0,0 +1,158 @@ + + + + + + + raspberrypi-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl + war + WSO2 Carbon - IoT Server RaspberryPi Controller API + WSO2 Carbon - RaspberryPi Controller Service API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + provided + + + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + raspberrypi + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/RaspberryPiControllerService.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/RaspberryPiControllerService.java new file mode 100644 index 000000000..1af824749 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/RaspberryPiControllerService.java @@ -0,0 +1,295 @@ +/* + * 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.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.common.AnalyticsDataRecord; +import org.wso2.carbon.device.mgt.analytics.exception.DeviceManagementAnalyticsException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature; +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.raspberrypi.controller.service.impl.dto.DeviceData; +import org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.dto.SensorData; +import org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.transport.RaspberryPiMQTTConnector; +import org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.util.RaspberrypiServiceUtils; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; +import org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +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.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +@API(name = "raspberrypi", version = "1.0.0", context = "/raspberrypi", tags = {"raspberrypi"}) +@DeviceType(value = "raspberrypi") +public class RaspberryPiControllerService { + + private static Log log = LogFactory.getLog(RaspberryPiControllerService.class); + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private ConcurrentHashMap deviceToIpMap = new ConcurrentHashMap<>(); + private RaspberryPiMQTTConnector raspberryPiMQTTConnector; + + private boolean waitForServerStartup() { + while (!IoTServerStartupListener.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + public RaspberryPiMQTTConnector getRaspberryPiMQTTConnector() { + return raspberryPiMQTTConnector; + } + + public void setRaspberryPiMQTTConnector( + final RaspberryPiMQTTConnector raspberryPiMQTTConnector) { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + RaspberryPiControllerService.this.raspberryPiMQTTConnector = raspberryPiMQTTConnector; + if (MqttConfig.getInstance().isEnabled()) { + raspberryPiMQTTConnector.connect(); + } else { + log.warn("MQTT disabled in 'devicemgt-config.xml'. Hence, RaspberryPiMQTTConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + @Path("controller/register/{deviceId}/{ip}/{port}") + @POST + public String registerDeviceIP(@PathParam("deviceId") String deviceId, @PathParam("ip") String deviceIP, + @PathParam("port") String devicePort, @Context HttpServletResponse response, + @Context HttpServletRequest request) { + try { + String result; + if (log.isDebugEnabled()) { + log.debug("Got register call from IP: " + deviceIP + " for Device ID: " + deviceId); + } + String deviceHttpEndpoint = deviceIP + ":" + devicePort; + deviceToIpMap.put(deviceId, deviceHttpEndpoint); + result = "Device-IP Registered"; + response.setStatus(Response.Status.OK.getStatusCode()); + if (log.isDebugEnabled()) { + log.debug(result); + } + return result; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + + @Path("controller/device/{deviceId}/bulb") + @POST + @Feature(code = "bulb", name = "Bulb On / Off", type = "operation", + description = "Switch on/off Raspberry Pi agent's bulb. (On / Off)") + public void switchBulb(@PathParam("deviceId") String deviceId, @FormParam("state") String state, + @Context HttpServletResponse response) { + try { + String switchToState = state.toUpperCase(); + if (!switchToState.equals(RaspberrypiConstants.STATE_ON) && !switchToState.equals( + RaspberrypiConstants.STATE_OFF)) { + log.error("The requested state change shoud be either - 'ON' or 'OFF'"); + response.setStatus(Response.Status.BAD_REQUEST.getStatusCode()); + return; + } + String callUrlPattern = RaspberrypiConstants.BULB_CONTEXT + switchToState; + try { + String deviceHTTPEndpoint = deviceToIpMap.get(deviceId); + if (deviceHTTPEndpoint == null) { + response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); + return; + } + RaspberrypiServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint, callUrlPattern, true); + } catch (DeviceManagementException e) { + log.error("Failed to send switch-bulb request to device [" + deviceId + "] via "); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return; + } + response.setStatus(Response.Status.OK.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("controller/device/{deviceId}/readtemperature") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Feature(code = "readtemperature", name = "Temperature", type = "monitor", + description = "Request temperature reading from Raspberry Pi agent") + public SensorRecord requestTemperature(@PathParam("deviceId") String deviceId, + @Context HttpServletResponse response) { + try { + SensorRecord sensorRecord = null; + if (log.isDebugEnabled()) { + log.debug("Sending request to read raspberrypi-temperature of device [" + deviceId + "] via "); + } + try { + String deviceHTTPEndpoint = deviceToIpMap.get(deviceId); + if (deviceHTTPEndpoint == null) { + response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); + } + String temperatureValue = RaspberrypiServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint, + RaspberrypiConstants + .TEMPERATURE_CONTEXT, + + false); + SensorDataManager.getInstance().setSensorRecord(deviceId, RaspberrypiConstants.SENSOR_TEMPERATURE, + temperatureValue, Calendar.getInstance() + .getTimeInMillis + ()); + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + RaspberrypiConstants + .SENSOR_TEMPERATURE); + } catch (DeviceManagementException | DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + response.setStatus(Response.Status.OK.getStatusCode()); + return sensorRecord; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("controller/push_temperature") + @POST + @Consumes(MediaType.APPLICATION_JSON) + public void pushTemperatureData(final DeviceData dataMsg, @Context HttpServletResponse response, + @Context HttpServletRequest request) { + try { + String owner = dataMsg.owner; + String deviceId = dataMsg.deviceId; + String deviceIp = dataMsg.reply; + float temperature = dataMsg.value; + String registeredIp = deviceToIpMap.get(deviceId); + if (registeredIp == null) { + log.warn("Unregistered IP: Temperature Data Received from an un-registered IP " + deviceIp + + " for device ID - " + deviceId); + response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); + return; + } else if (!registeredIp.equals(deviceIp)) { + log.warn("Conflicting IP: Received IP is " + deviceIp + ". Device with ID " + deviceId + + " is already registered under some other IP. Re-registration required"); + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return; + } + if (log.isDebugEnabled()) { + log.debug("Received Pin Data Value: " + temperature + " degrees C"); + } + SensorDataManager.getInstance().setSensorRecord(deviceId, RaspberrypiConstants.SENSOR_TEMPERATURE, + String.valueOf(temperature), + Calendar.getInstance().getTimeInMillis()); + if (!RaspberrypiServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.warn("An error occured whilst trying to publish temperature data of raspberrypi with ID [" + + deviceId + "] of owner [" + owner + "]"); + } + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Retreive Sensor data for the device type + */ + @Path("controller/stats/device/{deviceId}/sensors/temperature") + @GET + @Consumes("application/json") + @Produces("application/json") + public SensorData[] getArduinoTemperatureStats(@PathParam("deviceId") String deviceId, + @QueryParam("username") String user, + @QueryParam("from") long from, + @QueryParam("to") long to) { + + String fromDate = String.valueOf(from); + String toDate = String.valueOf(to); + List sensorDatas = new ArrayList<>(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + + RaspberrypiConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; + String sensorTableName = RaspberrypiConstants.TEMPERATURE_EVENT_TABLE; + try { + List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); + Collections.sort(records, new Comparator() { + @Override + public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { + long t1 = (Long) o1.getValue("time"); + long t2 = (Long) o2.getValue("time"); + if (t1 < t2) { + return -1; + } else if (t1 > t2) { + return 1; + } else { + return 0; + } + } + }); + for (AnalyticsDataRecord record : records) { + SensorData sensorData = new SensorData(); + sensorData.setTime((long) record.getValue("time")); + sensorData.setValue("" + (float) record.getValue(RaspberrypiConstants.SENSOR_TEMPERATURE)); + sensorDatas.add(sensorData); + } + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } catch (DeviceManagementAnalyticsException e) { + String errorMsg = "Error on retrieving stats on table " + sensorTableName + " with query " + query; + log.error(errorMsg); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/DeviceData.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/DeviceData.java new file mode 100644 index 000000000..6482d1e01 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/DeviceData.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceData { + @XmlElement(required = true) public String owner; + @XmlElement(required = true) public String deviceId; + @XmlElement(required = true) public String reply; + @XmlElement public Long time; + @XmlElement public String key; + @XmlElement public float value; +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/SensorData.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/SensorData.java new file mode 100644 index 000000000..4709b54f6 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/dto/SensorData.java @@ -0,0 +1,44 @@ +package org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +/** + * This stores sensor event data for the device type. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorData { + + @XmlElement public Long time; + @XmlElement public String key; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + @XmlElement public String value; + +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/exception/RaspberrypiException.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/exception/RaspberrypiException.java new file mode 100644 index 000000000..26fa4d538 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/exception/RaspberrypiException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.exception; + +public class RaspberrypiException extends Exception { + private static final long serialVersionUID = 118512086957330189L; + + public RaspberrypiException(String errorMessage) { + super(errorMessage); + } + + public RaspberrypiException(String errorMessage, Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/transport/RaspberryPiMQTTConnector.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/transport/RaspberryPiMQTTConnector.java new file mode 100644 index 000000000..d00da115b --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/transport/RaspberryPiMQTTConnector.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.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.wso2.carbon.context.PrivilegedCarbonContext; +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.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.util.RaspberrypiServiceUtils; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; +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 org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.io.File; +import java.util.Calendar; +import java.util.UUID; + +public class RaspberryPiMQTTConnector extends MQTTTransportHandler { + private static Log log = LogFactory.getLog(RaspberryPiMQTTConnector.class); + private static final String subscribeTopic = "wso2/" + RaspberrypiConstants.DEVICE_TYPE + "/+/publisher"; + + private static final String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5); + + private RaspberryPiMQTTConnector() { + super(iotServerSubscriber, RaspberrypiConstants.DEVICE_TYPE, + MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic); + } + + @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(); + } + + @Override + public void processIncomingMessage(MqttMessage message, String... messageParams) throws TransportHandlerException { + if(messageParams.length != 0) { + // owner and the deviceId are extracted from the MQTT topic to which the message was received. + // = [ServerName/Owner/DeviceType/DeviceId/"publisher"] + String topic = messageParams[0]; + String[] topicParams = topic.split("/"); + String deviceId = topicParams[2]; + String receivedMessage = message.toString(); + + if (log.isDebugEnabled()) { + log.debug("Received MQTT message for: [DEVICE.ID-" + deviceId + "]"); + log.debug("Message [" + receivedMessage + "] topic: [" + topic + "]"); + } + + if (receivedMessage.contains("PUBLISHER")) { + float temperature = Float.parseFloat(receivedMessage.split(":")[2]); + + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceManagementProviderService deviceManagementProviderService = + (DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + if (deviceManagementProviderService != null) { + DeviceIdentifier identifier = new DeviceIdentifier(deviceId, RaspberrypiConstants.DEVICE_TYPE); + Device device = deviceManagementProviderService.getDevice(identifier); + if (device != null) { + String owner = device.getEnrolmentInfo().getOwner(); + ctx.setTenantDomain(MultitenantUtils.getTenantDomain(owner), true); + ctx.setUsername(owner); + if (!RaspberrypiServiceUtils.publishToDAS(deviceId, temperature)) { + log.error("MQTT Subscriber: Publishing data to DAS failed."); + } + } + } + } catch (DeviceManagementException e) { + log.error("Failed to retreive the device managment service for device type " + + RaspberrypiConstants.DEVICE_TYPE, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + + if (log.isDebugEnabled()) { + log.debug("MQTT Subscriber: Published data to DAS successfully."); + } + + } else if (receivedMessage.contains("TEMPERATURE")) { + String temperatureValue = receivedMessage.split(":")[1]; + SensorDataManager.getInstance().setSensorRecord(deviceId, RaspberrypiConstants.SENSOR_TEMPERATURE, + temperatureValue, Calendar.getInstance().getTimeInMillis()); + } + } + } + + @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 + + " for device-type - " + RaspberrypiConstants.DEVICE_TYPE, e); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("MQTT-Terminator: Thread Sleep Interrupt Exception at device-type - " + + RaspberrypiConstants.DEVICE_TYPE, e1); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage() throws TransportHandlerException { + + } + + @Override + public void processIncomingMessage(MqttMessage message) throws TransportHandlerException { + + } + + @Override + public void publishDeviceData() throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(MqttMessage publishData) throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + + } +} + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/util/RaspberrypiServiceUtils.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/util/RaspberrypiServiceUtils.java new file mode 100644 index 000000000..a641ab09d --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/controller/service/impl/util/RaspberrypiServiceUtils.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; + +import javax.ws.rs.HttpMethod; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; + +public class RaspberrypiServiceUtils { + private static final Log log = LogFactory.getLog(RaspberrypiServiceUtils.class); + + //TODO; replace this tenant domain + private static final String SUPER_TENANT = "carbon.super"; + private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature"; + + public static String sendCommandViaHTTP(final String deviceHTTPEndpoint, String urlContext, + boolean fireAndForgot) throws DeviceManagementException { + + String responseMsg = ""; + String urlString = RaspberrypiConstants.URL_PREFIX + deviceHTTPEndpoint + urlContext; + + if (log.isDebugEnabled()) { + log.debug(urlString); + } + + if (!fireAndForgot) { + HttpURLConnection httpConnection = getHttpConnection(urlString); + + try { + httpConnection.setRequestMethod(HttpMethod.GET); + } catch (ProtocolException e) { + String errorMsg = + "Protocol specific error occurred when trying to set method to GET" + + " for:" + urlString; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + responseMsg = readResponseFromGetRequest(httpConnection); + + } else { + CloseableHttpAsyncClient httpclient = null; + try { + + httpclient = HttpAsyncClients.createDefault(); + httpclient.start(); + HttpGet request = new HttpGet(urlString); + final CountDownLatch latch = new CountDownLatch(1); + Future future = httpclient.execute( + request, new FutureCallback() { + @Override + public void completed(HttpResponse httpResponse) { + latch.countDown(); + } + + @Override + public void failed(Exception e) { + latch.countDown(); + } + + @Override + public void cancelled() { + latch.countDown(); + } + }); + + latch.await(); + + } catch (InterruptedException e) { + if (log.isDebugEnabled()) { + log.debug("Sync Interrupted"); + } + } finally { + try { + if (httpclient != null) { + httpclient.close(); + + } + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("Failed on close"); + } + } + } + } + + return responseMsg; + } + + + /*public static boolean sendCommandViaMQTT(String deviceOwner, String deviceId, String resource, + String state) throws DeviceManagementException { + + boolean result; + DeviceController deviceController = new DeviceController(); + + try { + result = deviceController.publishMqttControl(deviceOwner, RaspberrypiConstants.DEVICE_TYPE, deviceId, resource, state); + } catch (DeviceControllerException e) { + String errorMsg = "Error whilst trying to publish to MQTT Queue"; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + return result; + }*/ + + /* --------------------------------------------------------------------------------------- + Utility methods relevant to creating and sending http requests + --------------------------------------------------------------------------------------- */ + + /* This methods creates and returns a http connection object */ + + public static HttpURLConnection getHttpConnection(String urlString) throws + DeviceManagementException { + + URL connectionUrl = null; + HttpURLConnection httpConnection; + + try { + connectionUrl = new URL(urlString); + httpConnection = (HttpURLConnection) connectionUrl.openConnection(); + } catch (MalformedURLException e) { + String errorMsg = + "Error occured whilst trying to form HTTP-URL from string: " + urlString; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } catch (IOException e) { + String errorMsg = "Error occured whilst trying to open a connection to: " + + connectionUrl.toString(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + return httpConnection; + } + + /* This methods reads and returns the response from the connection */ + + public static String readResponseFromGetRequest(HttpURLConnection httpConnection) + throws DeviceManagementException { + BufferedReader bufferedReader; + try { + bufferedReader = new BufferedReader(new InputStreamReader( + httpConnection.getInputStream())); + } catch (IOException e) { + String errorMsg = + "There is an issue with connecting the reader to the input stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + String responseLine; + StringBuilder completeResponse = new StringBuilder(); + + try { + while ((responseLine = bufferedReader.readLine()) != null) { + completeResponse.append(responseLine); + } + } catch (IOException e) { + String errorMsg = + "Error occured whilst trying read from the connection stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + try { + bufferedReader.close(); + } catch (IOException e) { + log.error( + "Could not succesfully close the bufferedReader to the connection at: " + + httpConnection.getURL()); + } + + return completeResponse.toString(); + } + + public static boolean publishToDAS(String deviceId, float temperature) { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService( + DeviceAnalyticsService.class, null); + String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + Object metdaData[] = {owner, RaspberrypiConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; + Object payloadData[] = {temperature}; + try { + deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData, new Object[0], payloadData); + } catch (DataPublisherConfigurationException e) { + return false; + } + return true; + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..0ccfb9745 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..f2fe934b8 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,54 @@ + + + RaspberryPi + RaspberryPi + + + CXFServlet + org.apache.cxf.transport.servlet.CXFServlet + 1 + + + + + CXFServlet + /* + + + + isAdminService + false + + + doAuthentication + true + + + + + managed-api-enabled + true + + + managed-api-owner + admin + + + managed-api-context-template + /raspberrypi/{version} + + + managed-api-application + raspberrypi + + + managed-api-isSecured + true + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/pom.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/pom.xml new file mode 100644 index 000000000..9a2750ba3 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/pom.xml @@ -0,0 +1,166 @@ + + + + + + + raspberrypi-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl + war + WSO2 Carbon - IoT Server RaspberryPi Manager API + WSO2 Carbon - RaspberryPi Manager Service API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.jwt.client.extension + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.application.extension + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + raspberrypi_mgt + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/RaspberryPiManagerService.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/RaspberryPiManagerService.java new file mode 100644 index 000000000..abc970e89 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/RaspberryPiManagerService.java @@ -0,0 +1,323 @@ +/* + * 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.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey; +import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +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.controlqueue.xmpp.XmppAccount; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient; +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; +import org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl.util.APIUtil; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; +import org.wso2.carbon.device.mgt.iot.util.ZipArchive; +import org.wso2.carbon.device.mgt.iot.util.ZipUtil; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClient; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClientManager; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.user.api.UserStoreException; + +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; + +public class RaspberryPiManagerService { + + private static Log log = LogFactory.getLog(RaspberryPiManagerService.class); + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private static final String KEY_TYPE = "PRODUCTION"; + private static ApiApplicationKey apiApplicationKey; + + @Path("manager/device/register") + @POST + public boolean register(@QueryParam("deviceId") String deviceId, + @QueryParam("name") String name) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE); + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return false; + } + 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); + device.setName(name); + device.setType(RaspberrypiConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); + device.setEnrolmentInfo(enrolmentInfo); + 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()); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, + @Context HttpServletResponse response) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE); + 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()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @PUT + public boolean updateDevice(@PathParam("device_id") String deviceId, + @QueryParam("name") String name, + @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(RaspberrypiConstants.DEVICE_TYPE); + try { + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(RaspberrypiConstants.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; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @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(RaspberrypiConstants.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; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/devices") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Device[] getRaspberrypiDevices() { + try { + List userDevices = APIUtil.getDeviceManagementService().getDevicesOfUser( + APIUtil.getAuthenticatedUser()); + ArrayList usersRaspberrypiDevices = new ArrayList<>(); + for (Device device : userDevices) { + if (device.getType().equals(RaspberrypiConstants.DEVICE_TYPE) && + device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) { + usersRaspberrypiDevices.add(device); + } + } + return usersRaspberrypiDevices.toArray(new Device[]{}); + + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @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 (JWTClientException 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(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + + @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); + Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId()); + return rb.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 (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + + private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType) + throws DeviceManagementException, JWTClientException, APIManagerException, DeviceControllerException, + UserStoreException { + //create new device id + String deviceId = shortUUID(); + if (apiApplicationKey == null) { + String applicationUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration() + .getAdminUserName(); + APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); + String[] tags = {RaspberrypiConstants.DEVICE_TYPE}; + apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( + RaspberrypiConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); + } + JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + String scopes = "device_type_" + RaspberrypiConstants.DEVICE_TYPE + " device_" + deviceId; + AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), + apiApplicationKey.getConsumerSecret(), owner, scopes); + //create token + String accessToken = accessTokenInfo.getAccess_token(); + String refreshToken = accessTokenInfo.getRefresh_token(); + //adding registering data + XmppAccount newXmppAccount = new XmppAccount(); + newXmppAccount.setAccountName(owner + "_" + deviceId); + newXmppAccount.setUsername(deviceId); + newXmppAccount.setPassword(accessToken); + newXmppAccount.setEmail(deviceId + "@wso2.com"); + XmppServerClient xmppServerClient = new XmppServerClient(); + xmppServerClient.initControlQueue(); + boolean status; + if (XmppConfig.getInstance().isEnabled()) { + status = xmppServerClient.createXMPPAccount(newXmppAccount); + if (!status) { + String msg = "XMPP Account was not created for device - " + deviceId + " of owner - " + owner + + ".XMPP might have been disabled in org.wso2.carbon.device.mgt.iot.common.config" + + ".server.configs"; + log.warn(msg); + throw new DeviceManagementException(msg); + } + } + //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.getTenantDomainOftheUser(), sketchType, + deviceId, deviceName, accessToken, refreshToken); + zipFile.setDeviceId(deviceId); + return zipFile; + } + + 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); + } + +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/util/APIUtil.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/util/APIUtil.java new file mode 100644 index 000000000..412629443 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/manager/service/impl/util/APIUtil.java @@ -0,0 +1,55 @@ +package org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +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 { + + private static Log log = LogFactory.getLog(APIUtil.class); + + 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 getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String tenantDomain = threadLocalCarbonContext.getTenantDomain(); + return tenantDomain; + } + + 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static APIManagementProviderService getAPIManagementProviderService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + APIManagementProviderService apiManagementProviderService = + (APIManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + if (apiManagementProviderService == null) { + String msg = "API management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return apiManagementProviderService; + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..48216c9b8 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..abda0a6a4 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,50 @@ + + + RaspberryPi + RaspberryPi + + + 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 + /raspberrypi/{version} + + + managed-api-application + raspberrypi + + + managed-api-isSecured + true + + diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/pom.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/pom.xml new file mode 100644 index 000000000..8d96e651a --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/pom.xml @@ -0,0 +1,124 @@ + + + + + + + + raspberrypi-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl + bundle + WSO2 Carbon - IoT Server RaspberryPi Management Plugin + WSO2 Carbon - RaspberryPi Management/Control Plugin Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Impl Bundle + org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*, + javax.naming;resolution:=optional,, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers;resolution:=optional, + javax.net;resolution:=optional, + javax.net.ssl;resolution:=optional, + org.w3c.dom;resolution:=optional, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + org.wso2.carbon.device.mgt.extensions.feature.mgt.*, + org.wso2.carbon.utils.* + + + !org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.internal, + org.wso2.carbon.device.mgt.iot.raspberrypi.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 + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.utils + + + \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/constants/RaspberrypiConstants.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/constants/RaspberrypiConstants.java new file mode 100644 index 000000000..c6534e46f --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/constants/RaspberrypiConstants.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants; + +public class RaspberrypiConstants { + + public final static String DEVICE_TYPE = "raspberrypi"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "RASPBERRYPI_DEVICE_ID"; + public final static String STATE_ON = "ON"; + public final static String STATE_OFF = "OFF"; + + public static final String URL_PREFIX = "http://"; + public static final String BULB_CONTEXT = "/BULB/"; + public static final String TEMPERATURE_CONTEXT = "/TEMPERATURE/"; + + //type of the sensor + public static final String SENSOR_TEMPERATURE = "temperature"; + //sensor events summerized table name + public static final String TEMPERATURE_EVENT_TABLE = "ORG_WSO2_IOT_DEVICES_TEMPERATURE"; + public static final String DATA_SOURCE_NAME = "jdbc/RaspberryPiDM_DB"; + +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/exception/RaspberrypiDeviceMgtPluginException.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/exception/RaspberrypiDeviceMgtPluginException.java new file mode 100644 index 000000000..805775195 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/exception/RaspberrypiDeviceMgtPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.exception; + + +public class RaspberrypiDeviceMgtPluginException extends Exception{ + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public RaspberrypiDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public RaspberrypiDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public RaspberrypiDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public RaspberrypiDeviceMgtPluginException() { + super(); + } + + public RaspberrypiDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManager.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManager.java new file mode 100644 index 000000000..098438d46 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManager.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.exception.RaspberrypiDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.dao.RaspberrypiDAO; +import java.util.List; + +/** + * This represents the Raspberrypi implementation of DeviceManagerService. + */ +public class RaspberrypiManager implements DeviceManager { + + private static final RaspberrypiDAO raspberrypiDAO = new RaspberrypiDAO(); + private static final Log log = LogFactory.getLog(RaspberrypiManager.class); + + @Override + public FeatureManager getFeatureManager() { + return null; + } + + @Override + public boolean saveConfiguration(TenantConfiguration tenantConfiguration) + throws DeviceManagementException { + return false; + } + + @Override + public TenantConfiguration getConfiguration() throws DeviceManagementException { + return null; + } + + @Override + public boolean enrollDevice(Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new Raspberrypi device : " + device.getDeviceIdentifier()); + } + RaspberrypiDAO.beginTransaction(); + status = raspberrypiDAO.getDeviceDAO().addDevice(device); + RaspberrypiDAO.commitTransaction(); + } catch (RaspberrypiDeviceMgtPluginException e) { + try { + RaspberrypiDAO.rollbackTransaction(); + } catch (RaspberrypiDeviceMgtPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the Raspberrypi 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 Raspberrypi device enrollment data"); + } + RaspberrypiDAO.beginTransaction(); + status = raspberrypiDAO.getDeviceDAO().updateDevice(device); + RaspberrypiDAO.commitTransaction(); + } catch (RaspberrypiDeviceMgtPluginException e) { + try { + RaspberrypiDAO.rollbackTransaction(); + } catch (RaspberrypiDeviceMgtPluginException 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 Raspberrypi 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 Raspberrypi device : " + deviceId); + } + RaspberrypiDAO.beginTransaction(); + status = raspberrypiDAO.getDeviceDAO().deleteDevice(deviceId.getId()); + RaspberrypiDAO.commitTransaction(); + } catch (RaspberrypiDeviceMgtPluginException e) { + try { + RaspberrypiDAO.rollbackTransaction(); + } catch (RaspberrypiDeviceMgtPluginException 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 Raspberrypi 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 Raspberrypi device : " + deviceId.getId()); + } + Device iotDevice = raspberrypiDAO.getDeviceDAO().getDevice(deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (RaspberrypiDeviceMgtPluginException e) { + String msg = "Error while checking the enrollment status of Raspberrypi 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 Raspberrypi device : " + deviceId.getId()); + } + device = raspberrypiDAO.getDeviceDAO().getDevice(deviceId.getId()); + } catch (RaspberrypiDeviceMgtPluginException e) { + String msg = "Error while fetching the Raspberrypi 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 Raspberrypi device : " + deviceIdentifier); + } + RaspberrypiDAO.beginTransaction(); + status = raspberrypiDAO.getDeviceDAO().updateDevice(device); + RaspberrypiDAO.commitTransaction(); + } catch (RaspberrypiDeviceMgtPluginException e) { + try { + RaspberrypiDAO.rollbackTransaction(); + } catch (RaspberrypiDeviceMgtPluginException 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 Raspberrypi device : " + deviceIdentifier; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public List getAllDevices() throws DeviceManagementException { + List devices = null; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Raspberrypi devices"); + } + List iotDevices = raspberrypiDAO.getDeviceDAO().getAllDevices(); + } catch (RaspberrypiDeviceMgtPluginException e) { + String msg = "Error while fetching all Raspberrypi devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } +} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManagerService.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManagerService.java new file mode 100644 index 000000000..96ce170ef --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/RaspberrypiManagerService.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; + +import java.util.List; + +public class RaspberrypiManagerService implements DeviceManagementService { + + private DeviceManager deviceManager; + + @Override + public String getType() { + return RaspberrypiConstants.DEVICE_TYPE; + } + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return false; + } + + @Override + public void init() throws DeviceManagementException { + deviceManager = new RaspberrypiManager(); + } + + @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/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/RaspberrypiDAO.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/RaspberrypiDAO.java new file mode 100644 index 000000000..cdd317743 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/RaspberrypiDAO.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.exception.RaspberrypiDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.dao.impl.RaspberrypiDeviceDAOImpl; +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 RaspberrypiDAO { + + private static final Log log = LogFactory.getLog(RaspberrypiDAO.class); + static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal(); + + public RaspberrypiDAO() { + initRaspberrypiDAO(); + } + + public RaspberrypiDeviceDAOImpl getDeviceDAO() { + return new RaspberrypiDeviceDAOImpl(); + } + + public static void initRaspberrypiDAO() { + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(RaspberrypiConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + RaspberrypiConstants.DATA_SOURCE_NAME); + } + } + + public static void beginTransaction() throws RaspberrypiDeviceMgtPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new RaspberrypiDeviceMgtPluginException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws RaspberrypiDeviceMgtPluginException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new RaspberrypiDeviceMgtPluginException("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws RaspberrypiDeviceMgtPluginException { + 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 RaspberrypiDeviceMgtPluginException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws RaspberrypiDeviceMgtPluginException { + 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 RaspberrypiDeviceMgtPluginException { + 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 RaspberrypiDeviceMgtPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/impl/RaspberrypiDeviceDAOImpl.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/impl/RaspberrypiDeviceDAOImpl.java new file mode 100644 index 000000000..ae9c22620 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/dao/impl/RaspberrypiDeviceDAOImpl.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.exception.RaspberrypiDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.util.RaspberrypiUtils; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.dao.RaspberrypiDAO; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implements CRUD for Raspberrypi Devices. + */ +public class RaspberrypiDeviceDAOImpl { + + private static final Log log = LogFactory.getLog(RaspberrypiDeviceDAOImpl.class); + + public Device getDevice(String iotDeviceId) throws RaspberrypiDeviceMgtPluginException { + Connection conn; + PreparedStatement stmt = null; + Device device = null; + ResultSet resultSet = null; + try { + conn = RaspberrypiDAO.getConnection(); + String selectDBQuery = + "SELECT RASPBERRYPI_DEVICE_ID, DEVICE_NAME FROM RASPBERRYPI_DEVICE WHERE RASPBERRYPI_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, iotDeviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + device = new Device(); + device.setName(resultSet.getString(RaspberrypiConstants.DEVICE_PLUGIN_DEVICE_NAME)); + if (log.isDebugEnabled()) { + log.debug("Raspberrypi device " + iotDeviceId + " data has been fetched from " + + "Raspberrypi database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Raspberrypi device : '" + iotDeviceId + "'"; + log.error(msg, e); + throw new RaspberrypiDeviceMgtPluginException(msg, e); + } finally { + RaspberrypiUtils.cleanupResources(stmt, resultSet); + RaspberrypiDAO.closeConnection(); + } + return device; + } + + public boolean addDevice(Device device) throws RaspberrypiDeviceMgtPluginException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = RaspberrypiDAO.getConnection(); + String createDBQuery = + "INSERT INTO RASPBERRYPI_DEVICE(RASPBERRYPI_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, device.getDeviceIdentifier()); + stmt.setString(2, device.getName()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Raspberrypi device " + device.getDeviceIdentifier() + " data has been" + + " added to the Raspberrypi database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Raspberrypi device '" + + device.getDeviceIdentifier() + "' to the Raspberrypi db."; + log.error(msg, e); + throw new RaspberrypiDeviceMgtPluginException(msg, e); + } finally { + RaspberrypiUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device device) throws RaspberrypiDeviceMgtPluginException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = RaspberrypiDAO.getConnection(); + String updateDBQuery = "UPDATE RASPBERRYPI_DEVICE SET DEVICE_NAME = ? WHERE RASPBERRYPI_DEVICE_ID = ?"; + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, device.getName()); + stmt.setString(2, device.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Raspberrypi device " + device.getDeviceIdentifier() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Raspberrypi device '" + device.getDeviceIdentifier() + + "' data."; + log.error(msg, e); + throw new RaspberrypiDeviceMgtPluginException(msg, e); + } finally { + RaspberrypiUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteDevice(String iotDeviceId) throws RaspberrypiDeviceMgtPluginException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = RaspberrypiDAO.getConnection(); + String deleteDBQuery = "DELETE FROM RASPBERRYPI_DEVICE WHERE RASPBERRYPI_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, iotDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Raspberrypi device " + iotDeviceId + " data has deleted" + + " from the Raspberrypi database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Raspberrypi device " + iotDeviceId; + log.error(msg, e); + throw new RaspberrypiDeviceMgtPluginException(msg, e); + } finally { + RaspberrypiUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws RaspberrypiDeviceMgtPluginException { + Connection conn; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device device; + List devices = new ArrayList<>(); + try { + conn = RaspberrypiDAO.getConnection(); + String selectDBQuery = "SELECT RASPBERRYPI_DEVICE_ID, DEVICE_NAME FROM RASPBERRYPI_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + device = new Device(); + device.setDeviceIdentifier(resultSet.getString(RaspberrypiConstants.DEVICE_PLUGIN_DEVICE_ID)); + device.setName(resultSet.getString(RaspberrypiConstants.DEVICE_PLUGIN_DEVICE_NAME)); + devices.add(device); + } + if (log.isDebugEnabled()) { + log.debug("All Raspberrypi device details have fetched from Raspberrypi database."); + } + return devices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Raspberrypi device data'"; + log.error(msg, e); + throw new RaspberrypiDeviceMgtPluginException(msg, e); + } finally { + RaspberrypiUtils.cleanupResources(stmt, resultSet); + RaspberrypiDAO.closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/feature/RaspberrypiFeatureManager.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/feature/RaspberrypiFeatureManager.java new file mode 100644 index 000000000..755b7ae0d --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/feature/RaspberrypiFeatureManager.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.feature; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; + +import java.util.List; + +public class RaspberrypiFeatureManager implements FeatureManager { + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + return false; + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + return false; + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeature(RaspberrypiConstants.DEVICE_TYPE, name); + } + + @Override + public List getFeatures() throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeatures(RaspberrypiConstants.DEVICE_TYPE); + } + + @Override + public boolean removeFeature(String name) throws DeviceManagementException { + return false; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + return false; + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/DeviceSchemaInitializer.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/DeviceSchemaInitializer.java new file mode 100644 index 000000000..7919c4d76 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/DeviceSchemaInitializer.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * Provides methods for initializing the database script. + */ +public class DeviceSchemaInitializer extends DatabaseCreator{ + + private static final Log log = LogFactory.getLog(DeviceSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + + File.separator + "cdm" + File.separator + "plugins" + File.separator; + + public DeviceSchemaInitializer(DataSource dataSource) { + super(dataSource); + } + + @Override + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptName); + } + return setupSQLScriptBaseLocation.replaceFirst("DBTYPE", databaseType) + scriptName; + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/RaspberrypiUtils.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/RaspberrypiUtils.java new file mode 100644 index 000000000..bd0858141 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/impl/util/RaspberrypiUtils.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.constants.RaspberrypiConstants; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.exception.RaspberrypiDeviceMgtPluginException; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +/** + * Contains utility methods used by Raspberrypi plugin. + */ +public class RaspberrypiUtils { + + private static Log log = LogFactory.getLog(RaspberrypiUtils.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); + } + + /** + * Creates the device management schema. + */ + public static void setupDeviceManagementSchema() throws RaspberrypiDeviceMgtPluginException { + try { + Context ctx = new InitialContext(); + DataSource dataSource = (DataSource) ctx.lookup(RaspberrypiConstants.DATA_SOURCE_NAME); + DeviceSchemaInitializer initializer = + new DeviceSchemaInitializer(dataSource); + log.info("Initializing device management repository database schema"); + initializer.createRegistryDatabase(); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + RaspberrypiConstants.DATA_SOURCE_NAME); + } catch (Exception e) { + throw new RaspberrypiDeviceMgtPluginException("Error occurred while initializing Iot Device " + + "Management database schema", e); + } + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/internal/RaspberrypiManagementServiceComponent.java b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/internal/RaspberrypiManagementServiceComponent.java new file mode 100644 index 000000000..0b78f2d85 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/raspberrypi/plugin/internal/RaspberrypiManagementServiceComponent.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.raspberrypi.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.exception.RaspberrypiDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.RaspberrypiManagerService; +import org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl.util.RaspberrypiUtils; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.raspberrypi.internal.RaspberrypiManagementServiceComponent" + * immediate="true" + */ +public class RaspberrypiManagementServiceComponent { + + private ServiceRegistration raspberrypiServiceRegRef; + private static final Log log = LogFactory.getLog(RaspberrypiManagementServiceComponent.class); + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Raspberrypi Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + raspberrypiServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + new RaspberrypiManagerService(), null); + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug("-Dsetup is enabled. Iot Device management repository schema initialization is about " + + "to begin"); + } + try { + RaspberrypiUtils.setupDeviceManagementSchema(); + } catch (RaspberrypiDeviceMgtPluginException e) { + log.error("Exception occurred while initializing device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug("Raspberrypi Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error( + "Error occurred while activating Raspberrypi Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Raspberrypi Device Management Service Component"); + } + try { + if (raspberrypiServiceRegRef != null) { + raspberrypiServiceRegRef.unregister(); + } + if (log.isDebugEnabled()) { + log.debug("Raspberrypi Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Raspberrypi Device Management bundle", e); + } + } +} diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/pom.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/pom.xml new file mode 100644 index 000000000..29e8c9e80 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + raspberrypi-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.raspberrypi.ui + WSO2 Carbon - IoT Server RaspberryPi UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/assembly/src.xml b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.hbs b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.hbs new file mode 100644 index 000000000..d3c6c39b2 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.hbs @@ -0,0 +1,68 @@ +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "device-thumbnail"}} + +{{/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}} +
      +
      +
      Operations Log
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      +
      +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.js b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.js new file mode 100644 index 000000000..ea9439d4e --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.js @@ -0,0 +1,35 @@ +/* + * 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("detail.js"); + var deviceType = context.uriParams.deviceType; + var deviceId = request.getParameter("id"); + + 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") { + return {"device": device}; + } else { + response.sendError(404, "Device Id " + deviceId + "of type " + deviceType + " cannot be found!"); + exit(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.json b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/public/images/respberry-icon.png b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view/public/images/respberry-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fe7065142f65a256763557df31e1a2ef1cf8eb99 GIT binary patch literal 40558 zcmbrlW0Yh;w>DU|ZFSkUZQIIHmu=g&yVPadwz^zh?y~Kw$@hNueltJ5H9ux@tz3D| z$=Ew^cEpbT>?fj>6{Qg2@Zdl|KoDi5#Z^H-Kn?%%g#iOT5tZ3h0RG^*N@%;PIas)Q zm^cGKM9dvb0VFbZCYAtIfQh-6(*%GY1O(j4T3y>!TS1=J%)yS)#jaB5^Hk-GA#}TW(7wvfR(khw=+P^TT$K2`==R?Ihl|k z3BM;VP=Ou5)r7>;&eq?^ zFqkp3vXF4`FtTv4^RTecldv+guraYPGqLh8u(0s5bMdlplKl6F3|O19xdpGPxa5D= z1-ug=vvPHH&N9V(Q@LDnJHo>Hq42ouh)n|5j}8^4|jm95NBfssjG+X8a#ZyQq6P0+>_*E)H(aX2ADh@#BAlfn)doUeSLF0$anYBg@+TsZfeTH z$^Aci{!j7}EaKu4EX*Pz99$ACED{{tl58TPJRHnCTx=3N93mqBBP(O?;%Z`V2Kb-4 zt$}s_w=B>9t1PdWGr+{v!CBqG!S;WwK-tQ{)xpKe!I4BvjD%Xt+TPs3!-eKQZ|Hw@ zSRCMN?G7-Pbat>K`L7}7wf;X;4*;0_r+?-Q%qAul3;-5(0D~zTHz$JymxU=Sm#GYf`H29U;TTG;;A6mHMyof)*v%_Gr>&xjeM_y~mZyTk}M_y}wDEaCAcn~6n3 z;XZnWrB_#1_A=W61xKX{qLt)!vyH9fToYZ-Tkl)fxjqmpw|USL5{%ACF@+>|q=_;5 z|HvYsI>v!dtp0!A2nes;k)D`~oD!oTumnt$ULMGN93hwZN*~UXKo(b(3Kk~(im3@} zP1p63aP!qwH1$@rH?an|5pG#zCTw2ZhWPy@bY)*25TdL4DQ2dY4=J(bhpMZstEdRj z7A&X0)bhD+2oZqxdU9`QQZ_bA;pE`^K0P0Y_b@CoKV0B8DXFuwDOuedogV!wEullh z*T>Dz_-N!g!WaX`BqA!~sU`3x9311eQ zDdd$ouSCsQ)qT(ZGTkz^cWcdzKu1H{&ZDjK#Hw!GG)Y^9w&=X*5{-jzqLejei#0Ve zix3-<9gQZeU4L<)+Bk4;>^q8Z)#Z40GhoPQ9I4ye(A{V;)(}vP#wN_hq~)XKBM0(# zW;454;^Ts3gxvUz`!7op4m*|*;EEftS)n5WM~DQCylHlJOvOc zaA;7BoOOmbMpsfIjow(s;eRX_(-?48evz_(><2A^j;0J9Vqs*Am0IjPBm3bey~?60GI4kfg_gSFR6z$Q`R2B&?RFO1Mc2r$a!9*{pxIRaXtyKS&e< zwj$;PWOG8Nw!`L*ov~|*|`w-r02$SghRk9aiax~vmLo;IL8X8 zC@rEr6w}pJdAxn=2{O6u+{i|WM*NSdDpC{@Rk=RUTh+6$T^!q7n_6C(n?bdj)>F~Z zm>$_PW@xR>TRE)DY4U>AUyKc5`+uHeLHt-Uq%uI)QquGL<|gZ(tQU{zjV6i?VC*A$b!-^ZBrHS*~xc(Vsr`KN5eFdv0w6%em&9KF4wA}wD;=!j`kkgmFl#_Ho)Lr^?a&P-*U11snJ*ZFas?Q|UP&5+nH^snBx zo%N}24o;v2@&8;W;U%S@razL|)%z}tOm2iLvg3^vOifiXXkZXzkh0O>;bDhC<-i2^ z$eDo?G7v?BNi-CeOe-s$j}|G|R8Ho-^@J1sIzP*aq%pO#=Joq~Gx6*5jeC=AQ~O08 zDg~?g*4gFb>3-x%(_#i>&||;2Lv2i+NT3<9UqxRtibWV}acMY8akkra^?Tz}i-4%D z$%7Le+%B;DAlx$x_ta!(cCV6_E*P=3r2ri@r}=ozC~Tw@d6w8zupl%0m3;RyKBRoA zidi7w?+s{1{FQNUc5=So<<%cPC9o* zi&4cn8u=;4-P`#q^QaTbdE>&W4%fGn1WDxjGe9KCTAYYVb3+vP5naxR&2dDIcN`ZR zOLHspqqEDMt4kw0TWb@mC1<<;^?EQq|SEo5v zR;}kE0uS>tvu|f+hq8Decl=&Y-wyAy%=gB?sfc?KD5t5JV+qz9?7t$+B0VIiO7gkC z>jE4hf?&kC6k;Ek2-mL`HfwQDL154@h=6L+va|FIRq`->oAUhXsvL|Pw4>ol{NXHg zJ@wCCH|M^4UlDBOw!~IXkUF3Hd*dV8=-Vy;B!OP-_|6f&y>X@1p7PGN&PRDvb^XWL zIA=kSLMFq)_1}COy1`I>xrBdxHl--a%#Ph&LMt5h^Sf?O?((P#X7ainH$0gmqNl2i zGa>PWU+BM1*TPm!ocO-lmS&P3p4gUFA$RY%nOz4mHj(V!JNwG%?(wjyx8T&%PSFJu z6V)EB4_ps-+ooDSp7!k!!gUA*bo#WJPrK5Z$Q_6?Qd`}=uk&ja@iiID_k#nJUp8vq z2QY(^7FHGu3liiMck0g_-3?JWOV+CBne92;5Opgyk3*O@&CTZgblHX8jpP> zjH0$DW~QfUX(P;ophTa9{;NFG&3 zWpxM#E=4{jJG^Fomn*$2JOXrm73_T#5I1Xs`;B+ew0;JA#EUzBE_dFUY|imbm=#b< zI$J@fyEhZSYd@aJ=_z3^a5{N)+lU~s(liEP@a0VlpU~0qP^JrSUdro4f1aH&ZTlkN z2w4U8z)`XXoBzWQghg<3Yi?xcP@J0H3b-qnJk!0gk@0%`71$PtqxZ1?^J300g6QRd zEc44<(}H&i&Aa^2cHi;(CNuRR7c6pPoL8LXYln*1URUs!#%OTb&esJoMuX=OIW{!D z_ot9AZu8Yx2#&J}_!R5XAIL!X(Wj(@Q<F#Shtk zgZH}!(QZK02G{j{mb!UaE6nVOg#{M9B<_^|Dld-@d9x9#+}4R6Yu%!M}+8i}f@qFU|nFR?K2 z+E^SM=CDY3k17YX8@mwdHEy`dW-_|m{kyKP;^DpqI0HyP^Q!3G_Wc zsL$;i_GVPcLg{TkMJIXlM?aX}OJC1iaPh=t+m;1eAUwX{&oDC_;m{Vn=O9Sr-nYdC z!h>*Rl2=h?&oAu8DdQ7k2-^{@czd5)%8&A2$2THF9mL^H^tOL9e?{M&K>e#wwQQS= zhI@2-q@E1()UU>!A#J!fIH~*GQ6%DtBxjvCUH1x8aheERD6u%iN>4pJ!cJnz<_5+| z^KssuwTNP_FV{Ia$RA;I5D;a@A^JrpvRNz^%J`0;<0K9Vd-rxG1KP29MW67%8`_u)&B8FfF`SBctp!|m?-5Ww7F%6 zxL-21ACf@zJje6C@9lRr7?qKD1x)Ye0pf`W_+Xfb5(yq2%2%eC6}a}MaU!Uzv2wp@ zAnQtDeKRXPCl4df!9Yx5Vg1QPHyDNlE-!Vc0c;T(XRuFjt6i#K7R%Gpq0jGi3C}X} z^&87;&1%rtrc!H+Fg?R_1jm)C3tA2G9J zN0@%e(YejfjB8EsM$VthD;u4>w&F1TBWd*At0BR{}qC%4>==4Gn`#bHSM5^ZR{+W!hXwdM@b)#(g??TJ4{40JM>C| z*H=I@Ht{y7-!|}!n6is&%NE0*!Q8e6MvME(&zIksyr_BjoWjx_XaZ>nGu5%iFJo5l zGVKyA9LQIgzyIcB5`1`|1}DDbhQox`icrs)mbRBe7-1MOg4QmaiNJav zoxr!qjvbbK96mS_%xKV!Q86?@aYO+-i*jOIi>;Ma zv9}Vt$he-8AK}a9pXJ-7x$hq@x|=19oo{d80Wf4TWb`3d$cd>KcKg-pFo;{ z3uJSLj*;81xmgWWh7Cb^!V;n@VZRIP_;!ADiM7*&w5zL&x-zrO3pToiQ4_laf^l65 z0o@c|%QfFymVnf^_ZKArF{5q6!V}o^8K^X1~M+f&+v0_>rM?=%iOe@MmRM0MRJe~E#wBRF#?Dic=q{n^zZYeL0LNdVaC2yWk zHfVZ(qP}C!{JV7%qjV*o57Hlg_(E1gz#=n!psql}@&Sj}^Jc#1>JV4C%c+o&x560q z4k9h%K@5NsMteD*B2LK6!HLB=fz1a!lN5Gb+OPBfxL>XD7xWAL34tB~Ek&8z{f6QS zM)8AbTVU4M_$lDtx~a*8l2O0w-F0l>4-#kku0#Jw|D4PBcAw`t3(Me3xV#v6L%-Kc zV@cr#?Ws@YbrJ=aU1INFW z3OP`nQ^+$A6*?x)$K0InhU1}sR0X^+kTK%=DjQp2w2StKVEH|o^>0e63_T5Pgw3{E zpjhl0?*mE2V? zIOFaRhl~JA_hc?QI+JYT6GekLi-+Gfk}VRpf(%90GiO?>?+2(1&^~>zE@bLWk8b0RRStmXULJr*`VlAFPLy z1K}_(2u31>ogwqb1Fm&Bagt;4Y(ppmZBqU1fUMs4;5QN$$)(c8rtyUp)3LWw#a1lQ zKI_#YA+^Rk>S~juo^+ahl0S?}R`w#dxlv;4gJ{vgn`>*surYF=!u>m*Ita+P?O6&9 z>-reEzw)?^^f=N`ZH&UK%}g!q_ofQRhnsCTD0Ou-u+uVm$EPsmL;46H!=OU?M3^3@KaiE)|I!fO>nf}4>(($=vq-zGcGTy-n)BXcte@k zn0h|;VIvX{74Y@bXL5R=7xt^8mn=9TT2$f$H)U}yiDdquEKNq?eEmC^Oo=qMFsgro z8lI6e)Q9{rRb^wfL4rYe6ieLgT8%@{&c7KaLvX`rJfh2+d;xZ
    • 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

      R~8;NHV0F- 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 II*xb#4;5{2p#T5? literal 0 HcmV?d00001 diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/myDevices_analytics.png b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/myDevices_analytics.png new file mode 100644 index 0000000000000000000000000000000000000000..51d63966a4852e048c865a93d782c1299bed5d5c GIT binary patch literal 220158 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�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

    • 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≷KL?pb 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%0AP6P$HqAFSL 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 Twnn#+U;)I;#0p6^c8~iHx6;YM literal 0 HcmV?d00001 diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/thumb.png b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..510859d86cab2dbac49a30b96f213183593d0ea4 GIT binary patch literal 44816 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

      R~8;NHV0F- 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 II*xb#4;5{2p#T5? literal 0 HcmV?d00001 diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/download.js b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/download.js new file mode 100644 index 000000000..c8901643b --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/download.js @@ -0,0 +1,183 @@ +/* + * 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. + */ + +var modalPopup = ".wr-modalpopup"; +var modalPopupContainer = modalPopup + " .modalpopup-container"; +var modalPopupContent = modalPopup + " .modalpopup-content"; +var body = "body"; + +/* + * set popup maximum height function. + */ +function setPopupMaxHeight() { + $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30))); + $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2))); +} + +/* + * show popup function. + */ +function showPopup() { + $(modalPopup).show(); + setPopupMaxHeight(); + $('#downloadForm').validate({ + rules: { + deviceName: { + minlength: 4, + required: true + } + }, + highlight: function (element) { + $(element).closest('.control-group').removeClass('success').addClass('error'); + }, + success: function (element) { + $(element).closest('.control-group').removeClass('error').addClass('success'); + $('label[for=deviceName]').remove(); + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); +} + +/* + * hide popup function. + */ +function hidePopup() { + $('label[for=deviceName]').remove(); + $('.control-group').removeClass('success').removeClass('error'); + $(modalPopupContent).html(''); + $(modalPopup).hide(); +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + attachEvents(); +}); + +function attachEvents() { + /** + * Following click function would execute + * when a user clicks on "Download" link + * on Device Management page in WSO2 DC Console. + */ + $("a.download-link").click(function () { + var sketchType = $(this).data("sketchtype"); + var deviceType = $(this).data("devicetype"); + var downloadDeviceAPI = "/devicemgt/api/devices/sketch/generate_link"; + var payload = {"sketchType": sketchType, "deviceType": deviceType}; + $(modalPopupContent).html($('#download-device-modal-content').html()); + showPopup(); + var deviceName; + $("a#download-device-download-link").click(function () { + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + $('label[for=deviceName]').remove(); + if (deviceName && deviceName.length >= 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 deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/; + if (deviceName && deviceNameFormat.test(deviceName)) { + $('#downloadForm').submit(); + hidePopup(); + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + showPopup(); + setTimeout(function () { + hidePopup(); + }, 1000); + }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 == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showPopup(); + } else 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/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/jquery.validate.js b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.hbs b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.hbs new file mode 100644 index 000000000..67e4d0225 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.hbs @@ -0,0 +1,324 @@ +

      +

      Raspberry Pi

      +
      +
      + +
      + +
      + +
      +

      What it Does

      +
      +

      Connect a RaspberryPi to WSO2 IoT Server and manage it.

      +
      +

      What You Need

      +
      +
        +
      • + ITEM 01 +    Raspberry Pi with SD Card(Internet Enabled [Wifi or Ethernet]). +
      • +
      • + ITEM 02 +    Adafruit DHT11 Temperature Sensor. +
      • +
      • + ITEM 03 +    LED Bulb. +
      • +
      • + ITEM 04 +    Resister (eg : 470 ohm). +
      • +
      • + STEP 05 +    Proceed to [Prepare] section. +
      +
      + View API
        + + + Download Agent + +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +

      +
      +
      +

      Prepare

      +
      +
        +
      • + 01 +    Connect RaspberryPi, DHT11 Temperature sensor and LED as per the + schematic below. +
      • +
      • + 02 +    Ensure your RaspberryPi Board can connect to Internet. +
      • +
      • + 03 +    Download RaspberryPi Agent via [Download Agent] button above. + (Alternatively you can use the "curl" command to directly download the Agent to your + RaspberryPi.) +
      • +
      • + 04 +    Copy downloaded Agent into your RaspberryPi. +
      • +
      • + 05 +    Unzip the downloaded Agent and start terminal to run below commands. +
      • +
      • +                + + + + +    [sudo ./testAgent.sh]    -    Script to test agent + functionality. +
      • +
      • +                + + + + +    [sudo ./startService.sh]    -    Use this to start + agent as Daemon. +
      • +
      +
      +
      +
      +

      Schematic Diagram

      +
      +

      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 and monitor Real-Time data. +
      • +
      • + 03 +    You can also view analytics of the data published to IoT-Server by + navigating to Device Analytics page. +
      • +
      +
      +

      Click on the image to zoom

      +
      + + + +
      +
      + +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + {{js "/js/jquery.validate.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.json b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/org.wso2.carbon.device.mgt.iot.raspberrypi.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/raspberrypi-plugin/pom.xml b/components/iot-plugins/raspberrypi-plugin/pom.xml new file mode 100644 index 000000000..3b85d06d0 --- /dev/null +++ b/components/iot-plugins/raspberrypi-plugin/pom.xml @@ -0,0 +1,62 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + raspberrypi-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl + org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl + org.wso2.carbon.device.mgt.iot.raspberrypi.ui + org.wso2.carbon.device.mgt.iot.raspberrypi.analytics + org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/pom.xml new file mode 100644 index 000000000..99bbf77db --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/pom.xml @@ -0,0 +1,255 @@ + + + + + 4.0.0 + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl + WSO2 Carbon - IoT Server VirtualFireAlarm Advanced Agent + WSO2 Carbon - VirtualFireAlarm Device Advanced Agent Implementation + http://wso2.org + + + + + org.apache.maven.plugins + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + 2.3.2 + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.Bootstrap + + + + + jar-with-dependencies + + wso2-firealarm-virtual-agent-advanced + false + + + + make-assembly + + package + + + single + + + + + + + + + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + ${paho.mqtt.version} + + + + + org.igniterealtime.smack.wso2 + smack + ${smack.wso2.version} + + + org.igniterealtime.smack.wso2 + smackx + ${smackx.wso2.version} + + + + + org.bouncycastle.wso2 + bcprov-jdk15on + ${bcprov.wso2.version} + + + org.bouncycastle.wso2 + bcpkix-jdk15on + ${bcpkix.wso2.version} + + + + + com.google.code.jscep.wso2 + jscep + ${jscep.version} + + + + commons-codec.wso2 + commons-codec + + + + commons-lang + commons-lang + ${commons-lang.version} + + + + commons-logging + commons-logging + ${common-logging.version} + + + + commons-io + commons-io + ${commons.io} + + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + org.json.wso2 + json + + + + + org.wso2.siddhi + siddhi-query + ${sidhdhi.version} + + + org.wso2.siddhi + siddhi-core + ${sidhdhi.version} + + + + org.apache.httpcomponents + httpclient + ${apache-httpclient.version} + + + + com.google.code.gson + gson + ${gson.version} + + + + + + + + + wso2-nexus + WSO2 internal Repository + http://maven.wso2.org/nexus/content/groups/wso2-public/ + + true + daily + ignore + + + + wso2-maven2-repository + http://dist.wso2.org/maven2 + + + + + + 1.7 + 1.7 + + + 8.1.3.v20120416 + + + 1.0.2 + + + 3.0.4.wso2v1 + 3.0.4.wso2v1 + + + 1.49.wso2v1 + 1.49.wso2v1 + + + 2.0.2.wso2v2 + + + 1.2.17 + 1.2 + 2.4 + 1.7 + 2.6 + + + 4.5 + + + 1.7.13 + + + 2.1.0-wso2v1 + + 2.3.1 + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/Bootstrap.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/Bootstrap.java new file mode 100644 index 000000000..663a207f9 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/Bootstrap.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced; + +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; + +public class Bootstrap { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); + System.setProperty("org.apache.commons.logging.simplelog.defaultlog", "info"); + System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); + System.setProperty("org.apache.commons.logging.simplelog.dateTimeFormat", "HH:mm:ss"); + AgentManager.getInstance().init(); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/http/FireAlarmHTTPCommunicator.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/http/FireAlarmHTTPCommunicator.java new file mode 100644 index 000000000..bc4a7bfb7 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/http/FireAlarmHTTPCommunicator.java @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.communication.http; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.http.HTTPTransportHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.ProtocolException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class FireAlarmHTTPCommunicator extends HTTPTransportHandler { + private static final Log log = LogFactory.getLog(FireAlarmHTTPCommunicator.class); + + private ScheduledExecutorService service = Executors.newScheduledThreadPool(2); + private ScheduledFuture dataPushServiceHandler; + private ScheduledFuture connectorServiceHandler; + + public FireAlarmHTTPCommunicator() { + super(); + } + + public FireAlarmHTTPCommunicator(int port) { + super(port); + } + + public FireAlarmHTTPCommunicator(int port, int reconnectionInterval) { + super(port, reconnectionInterval); + } + + public ScheduledFuture getDataPushServiceHandler() { + return dataPushServiceHandler; + } + + public void connect() { + Runnable connect = new Runnable() { + public void run() { + if (!isConnected()) { + try { + processIncomingMessage(); + server.start(); + registerThisDevice(); + publishDeviceData(); + log.info("HTTP Server started at port: " + port); + + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn("Unable to 'START' HTTP server. Will retry after " + + timeoutInterval / 1000 + " seconds."); + } + } + } + } + }; + + connectorServiceHandler = service.scheduleAtFixedRate(connect, 0, timeoutInterval, + TimeUnit.MILLISECONDS); + } + + + @Override + public void processIncomingMessage() { + server.setHandler(new AbstractHandler() { + public void handle(String s, Request request, HttpServletRequest + httpServletRequest, + HttpServletResponse httpServletResponse) + throws IOException, ServletException { + httpServletResponse.setContentType("text/html;charset=utf-8"); + httpServletResponse.setStatus(HttpServletResponse.SC_OK); + request.setHandled(true); + + AgentManager agentManager = AgentManager.getInstance(); + String pathContext = request.getPathInfo(); + String separator = (File.separatorChar == '\\') ? ("\\\\") : (File.separator); + + if (pathContext.toUpperCase().contains( + separator + AgentConstants.TEMPERATURE_CONTROL)) { + httpServletResponse.getWriter().println( + agentManager.getTemperature()); + + } else if (pathContext.toUpperCase().contains( + separator + AgentConstants.HUMIDITY_CONTROL)) { + httpServletResponse.getWriter().println( + agentManager.getHumidity()); + + } else if (pathContext.toUpperCase().contains( + separator + AgentConstants.BULB_CONTROL)) { + String[] pathVariables = pathContext.split(separator); + + if (pathVariables.length != 3) { + httpServletResponse.getWriter().println( + "Invalid BULB-control received by the device. Need to be in " + + "'{host}:{port}/BULB/{ON|OFF}' format."); + return; + } + + String switchState = pathVariables[2]; + + if (switchState == null) { + httpServletResponse.getWriter().println( + "Please specify switch-status of the BULB."); + } else { + boolean status = switchState.toUpperCase().equals( + AgentConstants.CONTROL_ON); + agentManager.changeAlarmStatus(status); + httpServletResponse.getWriter().println("Bulb is " + (status ? + AgentConstants.CONTROL_ON : AgentConstants.CONTROL_OFF)); + } + } else { + httpServletResponse.getWriter().println( + "Invalid control command received by the device."); + } + } + }); + } + + @Override + public void publishDeviceData() { + final AgentManager agentManager = AgentManager.getInstance(); + int publishInterval = agentManager.getPushInterval(); + final String deviceOwner = agentManager.getAgentConfigs().getDeviceOwner(); + final String deviceID = agentManager.getAgentConfigs().getDeviceId(); + boolean simulationMode = false; + int duration = 2 * 60; + int frequency = 5; + + Runnable pushDataRunnable = new Runnable() { + @Override + public void run() { + + String pushDataPayload = String.format(AgentConstants.PUSH_DATA_PAYLOAD, deviceOwner, + deviceID, (agentManager.getDeviceIP() + ":" + port), + agentManager.getTemperature()); + executeDataPush(pushDataPayload); + } + }; + + if (!simulationMode) { + dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, + publishInterval, + TimeUnit.SECONDS); + } else { + String pushDataPayload = String.format(AgentConstants.PUSH_SIMULATION_DATA_PAYLOAD, deviceOwner, + deviceID, (agentManager.getDeviceIP() + ":" + port), + agentManager.getTemperature(), true, duration, frequency); + executeDataPush(pushDataPayload); + + } + } + + + private void executeDataPush(String pushDataPayload) { + AgentManager agentManager = AgentManager.getInstance(); + int responseCode = -1; + String pushDataEndPointURL = agentManager.getPushDataAPIEP(); + HttpURLConnection httpConnection = null; + + try { + httpConnection = TransportUtils.getHttpConnection(agentManager.getPushDataAPIEP()); + httpConnection.setRequestMethod(AgentConstants.HTTP_POST); + httpConnection.setRequestProperty("Authorization", "Bearer " + + agentManager.getAgentConfigs().getAuthToken()); + httpConnection.setRequestProperty("Content-Type", + AgentConstants.APPLICATION_JSON_TYPE); + + httpConnection.setDoOutput(true); + DataOutputStream dataOutPutWriter = new DataOutputStream( + httpConnection.getOutputStream()); + dataOutPutWriter.writeBytes(pushDataPayload); + dataOutPutWriter.flush(); + dataOutPutWriter.close(); + + responseCode = httpConnection.getResponseCode(); + httpConnection.disconnect(); + + log.info(AgentConstants.LOG_APPENDER + "Message - '" + pushDataPayload + + "' was published to server at: " + httpConnection.getURL()); + + } catch (ProtocolException exception) { + String errorMsg = + "Protocol specific error occurred when trying to set method to " + + AgentConstants.HTTP_POST + " for:" + pushDataEndPointURL; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + + } catch (IOException exception) { + String errorMsg = + "An IO error occurred whilst trying to get the response code from: " + + pushDataEndPointURL + " for a " + AgentConstants.HTTP_POST + + " " + "method."; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + + } catch (TransportHandlerException exception) { + log.error(AgentConstants.LOG_APPENDER + + "Error encountered whilst trying to create HTTP-Connection " + + "to IoT-Server EP at: " + + pushDataEndPointURL); + } + + if (responseCode == HttpStatus.CONFLICT_409 || + responseCode == HttpStatus.PRECONDITION_FAILED_412) { + log.warn(AgentConstants.LOG_APPENDER + + "DeviceIP is being Re-Registered due to Push-Data failure " + + "with response code: " + + responseCode); + registerThisDevice(); + + } else if (responseCode != HttpStatus.NO_CONTENT_204) { + if (log.isDebugEnabled()) { + log.error(AgentConstants.LOG_APPENDER + "Status Code: " + responseCode + + " encountered whilst trying to Push-Device-Data to IoT " + + "Server at: " + + agentManager.getPushDataAPIEP()); + } + agentManager.updateAgentStatus(AgentConstants.SERVER_NOT_RESPONDING); + } + + if (log.isDebugEnabled()) { + log.debug(AgentConstants.LOG_APPENDER + "Push-Data call with payload - " + + pushDataPayload + ", to IoT Server returned status " + + responseCode); + } + } + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + try { + dataPushServiceHandler.cancel(true); + connectorServiceHandler.cancel(true); + closeConnection(); + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn(AgentConstants.LOG_APPENDER + + "Unable to 'STOP' HTTP server at port: " + port); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + + "HTTP-Termination: Thread Sleep Interrupt " + + "Exception"); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage(Object message, String... messageParams) { + + } + + @Override + public void publishDeviceData(String... publishData) { + + } + + public void registerThisDevice() { + final AgentManager agentManager = AgentManager.getInstance(); + agentManager.updateAgentStatus("Registering..."); + + final Runnable ipRegistration = new Runnable() { + @Override + public void run() { + while (isConnected()) { + try { + int responseCode = registerDeviceIP( + agentManager.getAgentConfigs().getDeviceOwner(), + agentManager.getAgentConfigs().getDeviceId()); + + if (responseCode == HttpStatus.OK_200) { + agentManager.updateAgentStatus(AgentConstants.REGISTERED); + break; + } else { + log.error(AgentConstants.LOG_APPENDER + + "Device Registration with IoT Server at:" + " " + + agentManager.getIpRegistrationEP() + + " failed with response - '" + responseCode + ":" + + HttpStatus.getMessage(responseCode) + "'"); + agentManager.updateAgentStatus(AgentConstants.RETRYING_TO_REGISTER); + } + } catch (AgentCoreOperationException exception) { + log.error(AgentConstants.LOG_APPENDER + + "Error encountered whilst trying to register the " + + "Device's IP at: " + + agentManager.getIpRegistrationEP() + + ".\nCheck whether the network-interface provided is " + + "accurate"); + agentManager.updateAgentStatus(AgentConstants.REGISTRATION_FAILED); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + + "Device Registration: Thread Sleep Interrupt Exception"); + } + } + } + }; + + Thread ipRegisterThread = new Thread(ipRegistration); + ipRegisterThread.setDaemon(true); + ipRegisterThread.start(); + } + + + /** + * This method calls the "Register-API" of the IoT Server in order to register the device's IP + * against its ID. + * + * @param deviceOwner the owner of the device by whose name the agent was downloaded. + * (Read from configuration file) + * @param deviceID the deviceId that is auto-generated whilst downloading the agent. + * (Read from configuration file) + * @return the status code of the HTTP-Post call to the Register-API of the IoT-Server + * @throws AgentCoreOperationException if any errors occur when an HTTPConnection session is + * created + */ + private int registerDeviceIP(String deviceOwner, String deviceID) + throws AgentCoreOperationException { + int responseCode = -1; + final AgentManager agentManager = AgentManager.getInstance(); + + String networkInterface = agentManager.getNetworkInterface(); + String deviceIPAddress = getDeviceIP(networkInterface); + + if (deviceIPAddress == null) { + throw new AgentCoreOperationException( + "An IP address could not be retrieved for the selected network interface - '" + + networkInterface + "."); + } + + agentManager.setDeviceIP(deviceIPAddress); + log.info(AgentConstants.LOG_APPENDER + "Device IP Address: " + deviceIPAddress); + + String deviceIPRegistrationEP = agentManager.getIpRegistrationEP(); + String registerEndpointURLString = + deviceIPRegistrationEP + File.separator + deviceOwner + File.separator + deviceID + + File.separator + deviceIPAddress + File.separator + port; + + if (log.isDebugEnabled()) { + log.debug(AgentConstants.LOG_APPENDER + "DeviceIP Registration EndPoint: " + + registerEndpointURLString); + } + + HttpURLConnection httpConnection; + try { + httpConnection = TransportUtils.getHttpConnection(registerEndpointURLString); + } catch (TransportHandlerException e) { + String errorMsg = + "Protocol specific error occurred when trying to fetch an HTTPConnection to:" + + " " + + registerEndpointURLString; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(); + } + + try { + httpConnection.setRequestMethod(AgentConstants.HTTP_POST); + httpConnection.setRequestProperty("Authorization", "Bearer " + + agentManager.getAgentConfigs().getAuthToken()); + httpConnection.setDoOutput(true); + responseCode = httpConnection.getResponseCode(); + + } catch (ProtocolException exception) { + String errorMsg = "Protocol specific error occurred when trying to set method to " + + AgentConstants.HTTP_POST + " for:" + registerEndpointURLString; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, exception); + + } catch (IOException exception) { + String errorMsg = "An IO error occurred whilst trying to get the response code from:" + + " " + + registerEndpointURLString + " for a " + AgentConstants.HTTP_POST + " method."; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, exception); + } + + log.info(AgentConstants.LOG_APPENDER + "DeviceIP - " + deviceIPAddress + + ", registration with IoT Server at : " + + agentManager.getAgentConfigs().getHTTPS_ServerEndpoint() + + " returned status " + + responseCode); + + return responseCode; + } + + /*------------------------------------------------------------------------------------------*/ + /* Utility methods relevant to creating and sending HTTP requests to the Iot-Server */ + /*------------------------------------------------------------------------------------------*/ + + /** + * This method is used to get the IP of the device in which the agent is run on. + * + * @return the IP Address of the device + * @throws AgentCoreOperationException if any errors occur whilst trying to get the IP address + */ + private String getDeviceIP() throws AgentCoreOperationException { + try { + return Inet4Address.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + String errorMsg = "Error encountered whilst trying to get the device IP address."; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + } + + /** + * This is an overloaded method that fetches the public IPv4 address of the given network + * interface + * + * @param networkInterfaceName the network-interface of whose IPv4 address is to be retrieved + * @return the IP Address iof the device + * @throws AgentCoreOperationException if any errors occur whilst trying to get details of the + * given network interface + */ + private String getDeviceIP(String networkInterfaceName) throws + AgentCoreOperationException { + String ipAddress = null; + try { + Enumeration interfaceIPAddresses = NetworkInterface.getByName( + networkInterfaceName).getInetAddresses(); + for (; interfaceIPAddresses.hasMoreElements(); ) { + InetAddress ip = interfaceIPAddresses.nextElement(); + ipAddress = ip.getHostAddress(); + if (log.isDebugEnabled()) { + log.debug(AgentConstants.LOG_APPENDER + "IP Address: " + ipAddress); + } + + if (TransportUtils.validateIPv4(ipAddress)) { + return ipAddress; + } + } + } catch (SocketException | NullPointerException exception) { + String errorMsg = + "Error encountered whilst trying to get IP Addresses of the network interface: " + + networkInterfaceName + + ".\nPlease check whether the name of the network interface used is correct"; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, exception); + } + + return ipAddress; + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/mqtt/FireAlarmMQTTCommunicator.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/mqtt/FireAlarmMQTTCommunicator.java new file mode 100644 index 000000000..50e7f384e --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/mqtt/FireAlarmMQTTCommunicator.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.communication.mqtt; + +import com.google.gson.Gson; +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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.mqtt.MQTTTransportHandler; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class FireAlarmMQTTCommunicator extends MQTTTransportHandler { + + private static final Log log = LogFactory.getLog(FireAlarmMQTTCommunicator.class); + private static final Gson gson = new Gson(); + + private ScheduledExecutorService service = Executors.newScheduledThreadPool(2); + private ScheduledFuture dataPushServiceHandler; + + public FireAlarmMQTTCommunicator(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic) { + super(deviceOwner, deviceType, mqttBrokerEndPoint, subscribeTopic); + } + + @SuppressWarnings("unused") + public FireAlarmMQTTCommunicator(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic, + int intervalInMillis) { + super(deviceOwner, deviceType, mqttBrokerEndPoint, subscribeTopic, intervalInMillis); + } + + public ScheduledFuture getDataPushServiceHandler() { + return dataPushServiceHandler; + } + + //TODO:: Terminate logs with a period + //TODO: Need to print exceptions + @Override + public void connect() { + final AgentManager agentManager = AgentManager.getInstance(); + Runnable connector = new Runnable() { + public void run() { + while (!isConnected()) { + try { + connectToQueue(); + agentManager.updateAgentStatus("Connected to MQTT Queue"); + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Connection to MQTT Broker at: " + mqttBrokerEndPoint + + " failed.\n Will retry in " + timeoutInterval + " milli-seconds."); + } + + try { + subscribeToQueue(); + agentManager.updateAgentStatus("Subscribed to MQTT Queue"); + publishDeviceData(); + + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Subscription to MQTT Broker at: " + + mqttBrokerEndPoint + " failed"); + agentManager.updateAgentStatus("Subscription to broker failed."); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException ex) { + log.error(AgentConstants.LOG_APPENDER + "MQTT: Connect-Thread Sleep Interrupt Exception."); + } + } + } + }; + + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + + @Override + public void processIncomingMessage(MqttMessage message, String... messageParams) { + final AgentManager agentManager = AgentManager.getInstance(); + String serverName = agentManager.getAgentConfigs().getServerName(); + String deviceOwner = agentManager.getAgentConfigs().getDeviceOwner(); + String deviceID = agentManager.getAgentConfigs().getDeviceId(); + String receivedMessage; + String replyMessage; + String securePayLoad; + + try { + receivedMessage = message.toString(); + if(!receivedMessage.contains("POLICY")){ + receivedMessage = AgentUtilOperations.extractMessageFromPayload(receivedMessage); + } + log.info(AgentConstants.LOG_APPENDER + "Message [" + receivedMessage + "] was received"); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Could not extract message from payload.", e); + return; + } + + + String[] controlSignal = receivedMessage.split(":"); + // message- ":" format.(ex: "BULB:ON", "TEMPERATURE", "HUMIDITY") + + try { + switch (controlSignal[0].toUpperCase()) { + case AgentConstants.BULB_CONTROL: + boolean stateToSwitch = controlSignal[1].equals(AgentConstants.CONTROL_ON); + agentManager.changeAlarmStatus(stateToSwitch); + log.info( + AgentConstants.LOG_APPENDER + "Bulb was switched to state: '" + controlSignal[1] + "'"); + break; + + case AgentConstants.TEMPERATURE_CONTROL: + int currentTemperature = agentManager.getTemperature(); + + String replyTemperature = "Current temperature was read as: '" + currentTemperature + "C'"; + log.info(AgentConstants.LOG_APPENDER + replyTemperature); + + String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, + serverName, deviceOwner, deviceID); + + replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + publishToQueue(tempPublishTopic, securePayLoad); + break; + + case AgentConstants.HUMIDITY_CONTROL: + int currentHumidity = agentManager.getHumidity(); + + String replyHumidity = "Current humidity was read as: '" + currentHumidity + "%'"; + log.info(AgentConstants.LOG_APPENDER + replyHumidity); + + String humidPublishTopic = String.format( + AgentConstants.MQTT_PUBLISH_TOPIC, serverName, deviceOwner, deviceID); + + replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + publishToQueue(humidPublishTopic, securePayLoad); + break; + + case AgentConstants.POLICY_SIGNAL: + String policy = controlSignal[1]; + updateCEPPolicy(policy); + + default: + log.warn(AgentConstants.LOG_APPENDER + "'" + controlSignal[0] + + "' is invalid and not-supported for this device-type"); + break; + } + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e); + } catch (TransportHandlerException e) { + log.error(AgentConstants.LOG_APPENDER + + "MQTT - Publishing, reply message to the MQTT Queue at: " + + agentManager.getAgentConfigs().getMqttBrokerEndpoint() + " failed"); + } + + } + + @Override + public void publishDeviceData() { + final AgentManager agentManager = AgentManager.getInstance(); + int publishInterval = agentManager.getPushInterval(); + Runnable pushDataRunnable = new Runnable() { + @Override + public void run() { + int currentTemperature = agentManager.getTemperature(); + String message = "PUBLISHER:" + AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + + try { + String payLoad = AgentUtilOperations.prepareSecurePayLoad(message); + + MqttMessage pushMessage = new MqttMessage(); + pushMessage.setPayload(payLoad.getBytes(StandardCharsets.UTF_8)); + pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE); + pushMessage.setRetained(false); + + String topic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, + agentManager.getAgentConfigs().getServerName(), + agentManager.getAgentConfigs().getDeviceOwner(), + agentManager.getAgentConfigs().getDeviceId()); + + publishToQueue(topic, pushMessage); + log.info(AgentConstants.LOG_APPENDER + "Message: '" + message + "' published to MQTT Queue at [" + + agentManager.getAgentConfigs().getMqttBrokerEndpoint() + "] under topic [" + + topic + "]"); + + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Data Publish attempt to topic - [" + + AgentConstants.MQTT_PUBLISH_TOPIC + "] failed for payload [" + message + "]"); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e); + } + } + }; + + dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, publishInterval, + TimeUnit.SECONDS); + } + + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + + if (dataPushServiceHandler != null) { + dataPushServiceHandler.cancel(true); + } + + try { + closeConnection(); + + } catch (MqttException e) { + if (log.isDebugEnabled()) { + log.warn(AgentConstants.LOG_APPENDER + + "Unable to 'STOP' MQTT connection at broker at: " + + mqttBrokerEndPoint); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + + "MQTT-Terminator: Thread Sleep Interrupt Exception"); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage() { + + } + + @Override + public void publishDeviceData(String... publishData) { + + } + + private boolean isJSONValid(String JSON_STRING) { + try { + gson.fromJson(JSON_STRING, Object.class); + return true; + } catch (com.google.gson.JsonSyntaxException ex) { + return false; + } + } + + + private void updateCEPPolicy(String message) { + AgentManager agentManager = AgentManager.getInstance(); + System.out.println(" Message : " + message); + String fileLocation = agentManager.getRootPath() + AgentConstants.CEP_FILE_NAME; + message = AgentUtilOperations.formatMessage(message); + AgentUtilOperations.writeToFile(message, fileLocation); + agentManager.addToPolicyLog(message); + } + + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/xmpp/FireAlarmXMPPCommunicator.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/xmpp/FireAlarmXMPPCommunicator.java new file mode 100644 index 000000000..55c3cf1d0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/communication/xmpp/FireAlarmXMPPCommunicator.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.communication.xmpp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.packet.Message; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.xmpp.XMPPTransportHandler; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class FireAlarmXMPPCommunicator extends XMPPTransportHandler { + + private static final Log log = LogFactory.getLog(FireAlarmXMPPCommunicator.class); + + private ScheduledExecutorService service = Executors.newScheduledThreadPool(2); + private ScheduledFuture dataPushServiceHandler; + private ScheduledFuture connectorServiceHandler; + + private String username; + private String password; + private String resource; + private String xmppAdminJID; + private String xmppDeviceJID; + + public FireAlarmXMPPCommunicator(String server) { + super(server); + } + + public FireAlarmXMPPCommunicator(String server, int port) { + super(server, port); + } + + public FireAlarmXMPPCommunicator(String server, int port, int timeout) { + super(server, port, timeout); + } + + public ScheduledFuture getDataPushServiceHandler() { + return dataPushServiceHandler; + } + + @Override + public void connect() { + final AgentManager agentManager = AgentManager.getInstance(); + username = agentManager.getAgentConfigs().getDeviceId(); + password = agentManager.getAgentConfigs().getAuthToken(); + resource = agentManager.getAgentConfigs().getDeviceOwner(); + + xmppDeviceJID = username + "@" + server; + xmppAdminJID = agentManager.getAgentConfigs().getServerName() + "_" + AgentConstants.DEVICE_TYPE + "@" + server; + + + Runnable connect = new Runnable() { + public void run() { + if (!isConnected()) { + try { + connectToServer(); + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Connection to XMPP server at: " + server + " failed"); + } + + try { + loginToServer(username, password, resource); + agentManager.updateAgentStatus("Connected to XMPP Server"); + setMessageFilterAndListener(xmppAdminJID, xmppDeviceJID, true); + publishDeviceData(); + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Login to XMPP server at: " + server + " failed"); + agentManager.updateAgentStatus("No XMPP Account for Device"); + } + } + } + }; + + connectorServiceHandler = service.scheduleAtFixedRate(connect, 0, timeoutInterval, TimeUnit.MILLISECONDS); + } + + /** + * This is an abstract method used for post processing the received XMPP-message. This + * method will be implemented as per requirement at the time of creating an object of this + * class. + * + * @param xmppMessage the xmpp message received by the listener. + */ + @Override + public void processIncomingMessage(Message xmppMessage, String... messageParams) { + final AgentManager agentManager = AgentManager.getInstance(); + String from = xmppMessage.getFrom(); + String message = xmppMessage.getBody(); + String receivedMessage; + String replyMessage; + String securePayLoad; + + try { + receivedMessage = AgentUtilOperations.extractMessageFromPayload(message); + log.info(AgentConstants.LOG_APPENDER + "Message [" + receivedMessage + "] was received"); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Could not extract message from payload.", e); + return; + } + + String[] controlSignal = receivedMessage.split(":"); + //message- ":" format. (ex: "BULB:ON", "TEMPERATURE", "HUMIDITY") + + try { + switch (controlSignal[0].toUpperCase()) { + case AgentConstants.BULB_CONTROL: + if (controlSignal.length != 2) { + replyMessage = "BULB controls need to be in the form - 'BULB:{ON|OFF}'"; + log.warn(replyMessage); + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY"); + break; + } + + agentManager.changeAlarmStatus(controlSignal[1].equals(AgentConstants.CONTROL_ON)); + log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: '" + controlSignal[1] + "'"); + break; + + case AgentConstants.TEMPERATURE_CONTROL: + int currentTemperature = agentManager.getTemperature(); + + String replyTemperature = + "The current temperature was read to be: '" + currentTemperature + + "C'"; + log.info(AgentConstants.LOG_APPENDER + replyTemperature); + + replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY"); + break; + + case AgentConstants.HUMIDITY_CONTROL: + int currentHumidity = agentManager.getHumidity(); + + String replyHumidity = "The current humidity was read to be: '" + currentHumidity + "%'"; + log.info(AgentConstants.LOG_APPENDER + replyHumidity); + + replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY"); + break; + + default: + replyMessage = "'" + controlSignal[0] + "' is invalid and not-supported for this device-type"; + log.warn(replyMessage); + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-ERROR"); + break; + } + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e); + } + + } + + + @Override + public void publishDeviceData() { + final AgentManager agentManager = AgentManager.getInstance(); + int publishInterval = agentManager.getPushInterval(); + + Runnable pushDataRunnable = new Runnable() { + @Override + public void run() { + Message xmppMessage = new Message(); + + try { + int currentTemperature = agentManager.getTemperature(); + + String message = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + String payLoad = AgentUtilOperations.prepareSecurePayLoad(message); + + xmppMessage.setTo(xmppAdminJID); + xmppMessage.setSubject("PUBLISHER"); + xmppMessage.setBody(payLoad); + xmppMessage.setType(Message.Type.chat); + + sendXMPPMessage(xmppAdminJID, xmppMessage); + log.info(AgentConstants.LOG_APPENDER + "Message: '" + message + "' sent to XMPP JID - " + + "[" + xmppAdminJID + "] under subject [" + xmppMessage.getSubject() + "]."); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed for XMPP JID - " + + "[" + xmppAdminJID + "] with subject - [" + xmppMessage.getSubject() + "]."); + } + } + }; + + dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, + publishInterval, TimeUnit.SECONDS); + } + + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + + if (dataPushServiceHandler != null) { + dataPushServiceHandler.cancel(true); + } + + if (connectorServiceHandler != null) { + connectorServiceHandler.cancel(true); + } + + while (isConnected()) { + closeConnection(); + + if (log.isDebugEnabled()) { + log.warn(AgentConstants.LOG_APPENDER + + "Unable to 'STOP' connection to XMPP server at: " + server); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + "XMPP-Terminator: Thread Sleep Interrupt Exception"); + } + + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + + @Override + public void processIncomingMessage() { + + } + + @Override + public void publishDeviceData(String... publishData) { + + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConfiguration.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConfiguration.java new file mode 100644 index 000000000..49e437cc1 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConfiguration.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core; + +/** + * A Configuration class that holds all the Agent specific details that are read from the + * 'deviceConfig.properties' file. This file is generated by the IoT-Server at the time of + * downloading the device agent from the IoT-Server. + */ +public class AgentConfiguration { + private String serverName; + private String deviceOwner; + private String deviceId; + private String deviceName; + private String controllerContext; + private String HTTPS_ServerEndpoint; + private String HTTP_ServerEndpoint; + private String apimGatewayEndpoint; + private String mqttBrokerEndpoint; + private String xmppServerEndpoint; + private String authMethod; + private String authToken; + private String refreshToken; + private int dataPushInterval; + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getDeviceOwner() { + return deviceOwner; + } + + public void setDeviceOwner(String deviceOwner) { + this.deviceOwner = deviceOwner; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getControllerContext() { + return controllerContext; + } + + public void setControllerContext(String controllerContext) { + this.controllerContext = controllerContext; + } + + public String getHTTPS_ServerEndpoint() { + return HTTPS_ServerEndpoint; + } + + public void setHTTPS_ServerEndpoint(String HTTPS_ServerEndpoint) { + this.HTTPS_ServerEndpoint = HTTPS_ServerEndpoint; + } + + public String getHTTP_ServerEndpoint() { + return HTTP_ServerEndpoint; + } + + public void setHTTP_ServerEndpoint(String HTTP_ServerEndpoint) { + this.HTTP_ServerEndpoint = HTTP_ServerEndpoint; + } + + public String getApimGatewayEndpoint() { + return apimGatewayEndpoint; + } + + public void setApimGatewayEndpoint(String apimGatewayEndpoint) { + this.apimGatewayEndpoint = apimGatewayEndpoint; + } + + public String getMqttBrokerEndpoint() { + return mqttBrokerEndpoint; + } + + public void setMqttBrokerEndpoint(String mqttBrokerEndpoint) { + this.mqttBrokerEndpoint = mqttBrokerEndpoint; + } + + public String getXmppServerEndpoint() { + return xmppServerEndpoint; + } + + public void setXmppServerEndpoint(String xmppServerEndpoint) { + this.xmppServerEndpoint = xmppServerEndpoint; + } + + public String getAuthMethod() { + return authMethod; + } + + public void setAuthMethod(String authMethod) { + this.authMethod = authMethod; + } + + public String getAuthToken() { + return authToken; + } + + public void setAuthToken(String authToken) { + this.authToken = authToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public int getDataPushInterval() { + return dataPushInterval; + } + + public void setDataPushInterval(int dataPushInterval) { + this.dataPushInterval = dataPushInterval; + } +} + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConstants.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConstants.java new file mode 100644 index 000000000..038a52240 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentConstants.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core; + +public class AgentConstants { + public static final String DEVICE_TYPE = "virtual_firealarm"; + public static final String LOG_APPENDER = "AGENT_LOG:: "; + public static final String PROPERTIES_FILE_PATH = ""; + public static final int DEFAULT_RETRY_THREAD_INTERVAL = 5000; // time in millis + /* --------------------------------------------------------------------------------------- + IoT-Server specific information + --------------------------------------------------------------------------------------- */ + public static final String DEVICE_CONTROLLER_API_EP = "/virtual_firealarm/controller"; + public static final String DEVICE_ENROLLMENT_API_EP = "/scep"; + public static final String DEVICE_REGISTER_API_EP = "/register"; + public static final String DEVICE_PUSH_TEMPERATURE_API_EP = "/push_temperature"; + public static final String PUSH_DATA_PAYLOAD = + "{\"owner\":\"%s\",\"deviceId\":\"%s\",\"reply\":\"%s\",\"value\":\"%s\"}"; + + public static final String PUSH_SIMULATION_DATA_PAYLOAD = + "{\"owner\":\"%s\",\"deviceId\":\"%s\",\"reply\":\"%s\",\"value\":\"%s\",\"isSimulated\":\"%s\",\"duration\":\"%s\",\"frequency\":\"%s\"}"; + + public static final String AGENT_CONTROL_APP_EP = "/devicemgt/device/%s?id=%s"; + public static final String DEVICE_DETAILS_PAGE_EP = "/devicemgt/device/%s?id=%s"; + public static final String DEVICE_ANALYTICS_PAGE_URL = "/devicemgt/analytics?deviceId=%s&deviceType=%s&deviceName=%s"; + /* --------------------------------------------------------------------------------------- + HTTP Connection specific information for communicating with IoT-Server + --------------------------------------------------------------------------------------- */ + public static final String HTTP_POST = "POST"; + public static final String HTTP_GET = "GET"; + public static final String APPLICATION_JSON_TYPE = "application/json"; + public static final String REGISTERED = "Registered"; + public static final String NOT_REGISTERED = "Not-Registered"; + public static final String REGISTRATION_FAILED = "Registration Failed"; + public static final String RETRYING_TO_REGISTER = "Registration Failed. Re-trying.."; + public static final String SERVER_NOT_RESPONDING = "Server not responding.."; + + /* --------------------------------------------------------------------------------------- + MQTT Connection specific information + --------------------------------------------------------------------------------------- */ + public static final int DEFAULT_MQTT_RECONNECTION_INTERVAL = 2; // time in seconds + public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0; + public static final String MQTT_SUBSCRIBE_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s"; + public static final String MQTT_PUBLISH_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s/publisher"; + /* --------------------------------------------------------------------------------------- + XMPP Connection specific information + --------------------------------------------------------------------------------------- */ + public static final String XMPP_ADMIN_ACCOUNT_UNAME = "admin"; + /* --------------------------------------------------------------------------------------- + Device/Agent specific properties to be read from the 'deviceConfig.properties' file + --------------------------------------------------------------------------------------- */ + public static final String AGENT_PROPERTIES_FILE_NAME = "deviceConfig.properties"; + public static final String SERVER_NAME_PROPERTY = "server-name"; + public static final String DEVICE_OWNER_PROPERTY = "owner"; + public static final String DEVICE_ID_PROPERTY = "deviceId"; + public static final String DEVICE_NAME_PROPERTY = "device-name"; + public static final String DEVICE_CONTROLLER_CONTEXT_PROPERTY = "controller-context"; + public static final String SERVER_HTTPS_EP_PROPERTY = "https-ep"; + public static final String SERVER_HTTP_EP_PROPERTY = "http-ep"; + public static final String APIM_GATEWAY_EP_PROPERTY = "apim-ep"; + public static final String MQTT_BROKER_EP_PROPERTY = "mqtt-ep"; + public static final String XMPP_SERVER_EP_PROPERTY = "xmpp-ep"; + public static final String AUTH_METHOD_PROPERTY = "auth-method"; + public static final String AUTH_TOKEN_PROPERTY = "auth-token"; + public static final String REFRESH_TOKEN_PROPERTY = "refresh-token"; + public static final String NETWORK_INTERFACE_PROPERTY = "network-interface"; + public static final String PUSH_INTERVAL_PROPERTY = "push-interval"; + /* --------------------------------------------------------------------------------------- + Default values for the Device/Agent specific configurations listed above + --------------------------------------------------------------------------------------- */ + public static final String DEFAULT_SERVER_NAME = "WSO2IoTServer"; + public static final String DEFAULT_DEVICE_OWNER = "admin"; + public static final String DEFAULT_DEVICE_ID = "1234567890"; + public static final String DEFAULT_DEVICE_NAME = "admin_1234567890"; + public static final String DEFAULT_HTTPS_SERVER_EP = "https://localhost:9443"; + public static final String DEFAULT_HTTP_SERVER_EP = "http://localhost:9763"; + public static final String DEFAULT_APIM_GATEWAY_EP = "http://127.0.0.1:8281"; + public static final String DEFAULT_MQTT_BROKER_EP = "tcp://127.0.0.1:1883"; + public static final String DEFAULT_XMPP_SERVER_EP = "http://127.0.0.1:9061"; + public static final String DEFAULT_AUTH_METHOD = "token"; + public static final String DEFAULT_AUTH_TOKEN = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321"; + public static final String DEFAULT_REFRESH_TOKEN = "1234567890ZYXWVUTSRQPONMKLJIHGFEDCBA"; + public static final String DEFAULT_NETWORK_INTERFACE = "en0"; + public static final int DEFAULT_DATA_PUBLISH_INTERVAL = 15; // seconds + public static final String DEFAULT_PROTOCOL = "MQTT"; + /* --------------------------------------------------------------------------------------- + Control Signal specific constants to match the request context + --------------------------------------------------------------------------------------- */ + public static final String BULB_CONTROL = "BULB"; + public static final String TEMPERATURE_CONTROL = "TEMPERATURE"; + public static final String POLICY_SIGNAL = "POLICY"; + public static final String HUMIDITY_CONTROL = "HUMIDITY"; + public static final String CONTROL_ON = "ON"; + public static final String CONTROL_OFF = "OFF"; + public static final String AUDIO_FILE_NAME = "fireAlarmSound.mid"; + /* --------------------------------------------------------------------------------------- + Communication protocol specific Strings + --------------------------------------------------------------------------------------- */ + public static final String TCP_PREFIX = "tcp://"; + public static final String HTTP_PREFIX = "http://"; + public static final String HTTPS_PREFIX = "https://"; + public static final String HTTP_PROTOCOL = "HTTP"; + public static final String MQTT_PROTOCOL = "MQTT"; + public static final String XMPP_PROTOCOL = "XMPP"; + + public static final String CEP_FILE_NAME = "cep_query.txt"; + public static final String CEP_QUERY = "define stream fireAlarmEventStream (deviceID string, temp int);\n" + + "from fireAlarmEventStream#window.time(30 sec)\n" + + "select deviceID, max(temp) as maxValue\n" + + "group by deviceID\n" + + "insert into analyzeStream for expired-events;\n" + + "from analyzeStream[maxValue > 50]\n" + + "select maxValue\n" + + "insert into bulbOnStream;\n" + + "from fireAlarmEventStream[temp < 50]\n" + + "select deviceID, temp\n" + + "insert into bulbOffStream;"; + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentManager.java new file mode 100644 index 000000000..aba3809c3 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentManager.java @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.communication.http.FireAlarmHTTPCommunicator; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.communication.mqtt.FireAlarmMQTTCommunicator; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.communication.xmpp.FireAlarmXMPPCommunicator; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.enrollment.EnrollmentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.sidhdhi.SidhdhiQuery; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.virtual.VirtualHardwareManager; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AgentManager { + + private static final Log log = LogFactory.getLog(AgentManager.class); + private static final Object lock = new Object(); + private static AgentManager agentManager; + private static Boolean policyUpdated = false; + private String rootPath = ""; + private boolean deviceReady = false; + private boolean isAlarmOn = false; + private String initialPolicy; + + private String deviceMgtControlUrl, deviceMgtAnalyticUrl; + private String deviceName, agentStatus; + + private int pushInterval; // seconds + private String prevProtocol, protocol; + + private String networkInterface; + private List interfaceList, protocolList; + private Map agentCommunicator; + + private AgentConfiguration agentConfigs; + + private String deviceIP; + private String enrollmentEP; + private String ipRegistrationEP; + private String pushDataAPIEP; + + private AgentManager() { + } + + public static synchronized AgentManager getInstance() { + if (agentManager == null) { + agentManager = new AgentManager(); + } + return agentManager; + } + + public static void setUpdated(Boolean isUpdated) { + synchronized (lock) { + policyUpdated = isUpdated; + } + } + + public static Boolean isUpdated() { + synchronized (lock) { + Boolean temp = policyUpdated; + policyUpdated = false; + return temp; + } + } + + public void init() { + + agentCommunicator = new HashMap<>(); + + // Read IoT-Server specific configurations from the 'deviceConfig.properties' file + this.agentConfigs = AgentUtilOperations.readIoTServerConfigs(); + + // Initialise IoT-Server URL endpoints from the configuration read from file + AgentUtilOperations.initializeServerEndPoints(); + + String analyticsPageContext = String.format(AgentConstants.DEVICE_ANALYTICS_PAGE_URL, + agentConfigs.getDeviceId(), + AgentConstants.DEVICE_TYPE, + agentConfigs.getDeviceName()); + + String controlPageContext = String.format(AgentConstants.DEVICE_DETAILS_PAGE_EP, + AgentConstants.DEVICE_TYPE, + agentConfigs.getDeviceId()); + + this.deviceMgtAnalyticUrl = agentConfigs.getHTTPS_ServerEndpoint() + analyticsPageContext; + this.deviceMgtControlUrl = agentConfigs.getHTTPS_ServerEndpoint() + controlPageContext; + + this.agentStatus = AgentConstants.NOT_REGISTERED; + this.deviceName = this.agentConfigs.getDeviceName(); + + this.pushInterval = this.agentConfigs.getDataPushInterval(); + this.networkInterface = AgentConstants.DEFAULT_NETWORK_INTERFACE; + + this.protocol = AgentConstants.DEFAULT_PROTOCOL; + this.prevProtocol = protocol; + + Map xmppIPPortMap; + try { + xmppIPPortMap = TransportUtils.getHostAndPort(agentConfigs.getXmppServerEndpoint()); + String xmppServer = xmppIPPortMap.get("Host"); + int xmppPort = Integer.parseInt(xmppIPPortMap.get("Port")); + + TransportHandler xmppCommunicator = new FireAlarmXMPPCommunicator(xmppServer, xmppPort); + agentCommunicator.put(AgentConstants.XMPP_PROTOCOL, xmppCommunicator); + + } catch (TransportHandlerException e) { + log.error("XMPP Endpoint String - " + agentConfigs.getXmppServerEndpoint() + + ", provided in the configuration file is invalid."); + } + String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC, + agentConfigs.getServerName(), + agentConfigs.getDeviceOwner(), + agentConfigs.getDeviceId()); + +// TransportHandler httpCommunicator = new FireAlarmHTTPCommunicator(); + TransportHandler mqttCommunicator = new FireAlarmMQTTCommunicator(agentConfigs.getDeviceOwner(), + agentConfigs.getDeviceId(), + agentConfigs.getMqttBrokerEndpoint(), + mqttTopic); + +// agentCommunicator.put(AgentConstants.HTTP_PROTOCOL, httpCommunicator); + agentCommunicator.put(AgentConstants.MQTT_PROTOCOL, mqttCommunicator); + + try { + interfaceList = new ArrayList<>(TransportUtils.getInterfaceIPMap().keySet()); + protocolList = new ArrayList<>(agentCommunicator.keySet()); + } catch (TransportHandlerException e) { + log.error("An error occurred whilst retrieving all NetworkInterface-IP mappings"); + } + + String siddhiQueryFilePath = rootPath + AgentConstants.CEP_FILE_NAME; + (new Thread(new SidhdhiQuery())).start(); + initialPolicy = SidhdhiQuery.readFile(siddhiQueryFilePath, StandardCharsets.UTF_8); + + //Initializing hardware at that point + //AgentManger.setDeviceReady() method should invoked from hardware after initialization + VirtualHardwareManager.getInstance().init(); + + //Wait till hardware get ready + while (!deviceReady) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + log.info(AgentConstants.LOG_APPENDER + "Sleep error in 'device ready-flag' checking thread"); + } + } + + try { + EnrollmentManager.getInstance().beginEnrollmentFlow(); + } catch (AgentCoreOperationException e) { + log.error("Device Enrollment Failed:\n"); + e.printStackTrace(); + System.exit(0); + } + + //Start agent communication + agentCommunicator.get(protocol).connect(); + } + + private void switchCommunicator(String stopProtocol, String startProtocol) { + agentCommunicator.get(stopProtocol).disconnect(); + + while (agentCommunicator.get(stopProtocol).isConnected()) { + try { + Thread.sleep(250); + } catch (InterruptedException e) { + log.info(AgentConstants.LOG_APPENDER + + "Sleep error in 'Switch-Communicator' Thread's shutdown wait."); + } + } + + agentCommunicator.get(startProtocol).connect(); + } + + public void setInterface(int interfaceId) { + if (interfaceId != -1) { + String newInterface = interfaceList.get(interfaceId); + + if (!newInterface.equals(networkInterface)) { + networkInterface = newInterface; + + if (protocol.equals(AgentConstants.HTTP_PROTOCOL) && !protocol.equals( + prevProtocol)) { + switchCommunicator(protocol, protocol); + } + } + } + } + + public void setProtocol(int protocolId) { + if (protocolId != -1) { + String newProtocol = protocolList.get(protocolId); + + if (!protocol.equals(newProtocol)) { + prevProtocol = protocol; + protocol = newProtocol; + switchCommunicator(prevProtocol, protocol); + } + } + } + + public void changeAlarmStatus(boolean isOn) { + VirtualHardwareManager.getInstance().changeAlarmStatus(isOn); + isAlarmOn = isOn; + } + + public void updateAgentStatus(String status) { + this.agentStatus = status; + } + + public void addToPolicyLog(String policy) { + VirtualHardwareManager.getInstance().addToPolicyLog(policy); + } + + public String getRootPath() { + return rootPath; + } + + /*------------------------------------------------------------------------------------------*/ + /* Getter and Setter Methods for the private variables */ + /*------------------------------------------------------------------------------------------*/ + + public void setRootPath(String rootPath) { + this.rootPath = rootPath; + } + + public void setDeviceReady(boolean deviceReady) { + this.deviceReady = deviceReady; + } + + public String getInitialPolicy() { + return initialPolicy; + } + + public String getDeviceMgtControlUrl() { + return deviceMgtControlUrl; + } + + public String getDeviceMgtAnalyticUrl() { + return deviceMgtAnalyticUrl; + } + + public AgentConfiguration getAgentConfigs() { + return agentConfigs; + } + + public String getDeviceIP() { + return deviceIP; + } + + public void setDeviceIP(String deviceIP) { + this.deviceIP = deviceIP; + } + + public String getEnrollmentEP() { + return enrollmentEP; + } + + public void setEnrollmentEP(String enrollmentEP) { + this.enrollmentEP = enrollmentEP; + } + + public String getIpRegistrationEP() { + return ipRegistrationEP; + } + + public void setIpRegistrationEP(String ipRegistrationEP) { + this.ipRegistrationEP = ipRegistrationEP; + } + + public String getPushDataAPIEP() { + return pushDataAPIEP; + } + + public void setPushDataAPIEP(String pushDataAPIEP) { + this.pushDataAPIEP = pushDataAPIEP; + } + + public String getDeviceName() { + return deviceName; + } + + public String getNetworkInterface() { + return networkInterface; + } + + public String getAgentStatus() { + return agentStatus; + } + + public int getPushInterval() { + return pushInterval; + } + + public void setPushInterval(int pushInterval) { + this.pushInterval = pushInterval; + TransportHandler transportHandler = agentCommunicator.get(protocol); + + switch (protocol) { + case AgentConstants.HTTP_PROTOCOL: + ((FireAlarmHTTPCommunicator) transportHandler).getDataPushServiceHandler() + .cancel(true); + break; + case AgentConstants.MQTT_PROTOCOL: + ((FireAlarmMQTTCommunicator) transportHandler).getDataPushServiceHandler() + .cancel(true); + break; + case AgentConstants.XMPP_PROTOCOL: + ((FireAlarmXMPPCommunicator) transportHandler).getDataPushServiceHandler() + .cancel(true); + break; + default: + log.warn("Unknown protocol " + protocol); + } + transportHandler.publishDeviceData(); + + if (log.isDebugEnabled()) { + log.debug("The Data Publish Interval was changed to: " + pushInterval); + } + } + + public List getInterfaceList() { + return interfaceList; + } + + public List getProtocolList() { + return protocolList; + } + + /** + * Get temperature reading from device + * + * @return Temperature + */ + public int getTemperature() { + return VirtualHardwareManager.getInstance().getTemperature(); + } + + /** + * Get humidity reading from device + * + * @return Humidity + */ + public int getHumidity() { + return VirtualHardwareManager.getInstance().getHumidity(); + } + + public boolean isAlarmOn() { + return isAlarmOn; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentUtilOperations.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentUtilOperations.java new file mode 100644 index 000000000..cb2dbf4d1 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/core/AgentUtilOperations.java @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.enrollment.EnrollmentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.CommunicationUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; + +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Properties; + +/** + * This class contains all the core operations of the FireAlarm agent that are common to both + * Virtual and Real Scenarios. These operations include, connecting to and subscribing to an MQTT + * queue and to a XMPP Server. Pushing temperature data to the IoT-Server at timely intervals. + * Reading device specific configuration from a configs file etc.... + */ +public class AgentUtilOperations { + + private static final Log log = LogFactory.getLog(AgentUtilOperations.class); + private static final String JSON_MESSAGE_KEY = "Msg"; + private static final String JSON_SIGNATURE_KEY = "Sig"; + + /** + * This method reads the agent specific configurations for the device from the + * "deviceConfigs.properties" file found at /repository/conf folder. + * If the properties file is not found in the specified path, then the configuration values + * are set to the default ones in the 'AgentConstants' class. + * + * @return an object of type 'AgentConfiguration' which contains all the necessary + * configuration attributes + */ + public static AgentConfiguration readIoTServerConfigs() { + AgentManager agentManager = AgentManager.getInstance(); + AgentConfiguration iotServerConfigs = new AgentConfiguration(); + Properties properties = new Properties(); + InputStream propertiesInputStream = null; + String propertiesFileName = AgentConstants.AGENT_PROPERTIES_FILE_NAME; + + try { + ClassLoader loader = AgentUtilOperations.class.getClassLoader(); + URL path = loader.getResource(propertiesFileName); + System.out.println(path); + String root = path.getPath().replace( + "wso2-firealarm-virtual-agent-advanced.jar!/deviceConfig.properties", + "").replace("jar:", "").replace("file:", ""); + + agentManager.setRootPath(root); + + propertiesInputStream = new FileInputStream( + root + AgentConstants.AGENT_PROPERTIES_FILE_NAME); + + //load a properties file from class path, inside static method + properties.load(propertiesInputStream); + + iotServerConfigs.setServerName(properties.getProperty( + AgentConstants.SERVER_NAME_PROPERTY)); + iotServerConfigs.setDeviceOwner(properties.getProperty( + AgentConstants.DEVICE_OWNER_PROPERTY)); + iotServerConfigs.setDeviceId(properties.getProperty( + AgentConstants.DEVICE_ID_PROPERTY)); + iotServerConfigs.setDeviceName(properties.getProperty( + AgentConstants.DEVICE_NAME_PROPERTY)); + iotServerConfigs.setControllerContext(properties.getProperty( + AgentConstants.DEVICE_CONTROLLER_CONTEXT_PROPERTY)); + iotServerConfigs.setHTTPS_ServerEndpoint(properties.getProperty( + AgentConstants.SERVER_HTTPS_EP_PROPERTY)); + iotServerConfigs.setHTTP_ServerEndpoint(properties.getProperty( + AgentConstants.SERVER_HTTP_EP_PROPERTY)); + iotServerConfigs.setApimGatewayEndpoint(properties.getProperty( + AgentConstants.APIM_GATEWAY_EP_PROPERTY)); + iotServerConfigs.setMqttBrokerEndpoint(properties.getProperty( + AgentConstants.MQTT_BROKER_EP_PROPERTY)); + iotServerConfigs.setXmppServerEndpoint(properties.getProperty( + AgentConstants.XMPP_SERVER_EP_PROPERTY)); + iotServerConfigs.setAuthMethod(properties.getProperty( + AgentConstants.AUTH_METHOD_PROPERTY)); + iotServerConfigs.setAuthToken(properties.getProperty( + AgentConstants.AUTH_TOKEN_PROPERTY)); + iotServerConfigs.setRefreshToken(properties.getProperty( + AgentConstants.REFRESH_TOKEN_PROPERTY)); + iotServerConfigs.setDataPushInterval(Integer.parseInt(properties.getProperty( + AgentConstants.PUSH_INTERVAL_PROPERTY))); + + log.info(AgentConstants.LOG_APPENDER + "Server name: " + + iotServerConfigs.getServerName()); + log.info(AgentConstants.LOG_APPENDER + "Device Owner: " + + iotServerConfigs.getDeviceOwner()); + log.info(AgentConstants.LOG_APPENDER + "Device ID: " + iotServerConfigs.getDeviceId()); + log.info(AgentConstants.LOG_APPENDER + "Device Name: " + + iotServerConfigs.getDeviceName()); + log.info(AgentConstants.LOG_APPENDER + "Device Controller Context: " + + iotServerConfigs.getControllerContext()); + log.info(AgentConstants.LOG_APPENDER + "IoT Server HTTPS EndPoint: " + + iotServerConfigs.getHTTPS_ServerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "IoT Server HTTP EndPoint: " + + iotServerConfigs.getHTTP_ServerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "API-Manager Gateway EndPoint: " + + iotServerConfigs.getApimGatewayEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "MQTT Broker EndPoint: " + + iotServerConfigs.getMqttBrokerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "XMPP Server EndPoint: " + + iotServerConfigs.getXmppServerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "Authentication Method: " + + iotServerConfigs.getAuthMethod()); + log.info(AgentConstants.LOG_APPENDER + "Authentication Token: " + + iotServerConfigs.getAuthToken()); + log.info(AgentConstants.LOG_APPENDER + "Refresh Token: " + + iotServerConfigs.getRefreshToken()); + log.info(AgentConstants.LOG_APPENDER + "Data Push Interval: " + + iotServerConfigs.getDataPushInterval()); + + } catch (FileNotFoundException ex) { + log.error(AgentConstants.LOG_APPENDER + "Unable to find " + propertiesFileName + + " file at: " + AgentConstants.PROPERTIES_FILE_PATH); + iotServerConfigs = setDefaultDeviceConfigs(); + + } catch (IOException ex) { + log.error(AgentConstants.LOG_APPENDER + "Error occurred whilst trying to fetch '" + + propertiesFileName + "' from: " + + AgentConstants.PROPERTIES_FILE_PATH); + iotServerConfigs = setDefaultDeviceConfigs(); + + } finally { + if (propertiesInputStream != null) { + try { + propertiesInputStream.close(); + } catch (IOException e) { + log.error(AgentConstants.LOG_APPENDER + + "Error occurred whilst trying to close InputStream resource used to read the '" + + propertiesFileName + "' file"); + } + } + } + return iotServerConfigs; + } + + /** + * Sets the default Device specific configurations listed in the 'AgentConstants' class. + * + * @return an object of AgentConfiguration class including all default device specific configs. + */ + private static AgentConfiguration setDefaultDeviceConfigs() { + log.warn(AgentConstants.LOG_APPENDER + + "Default Values are being set to all Agent specific configurations"); + + AgentConfiguration iotServerConfigs = new AgentConfiguration(); + + iotServerConfigs.setDeviceOwner(AgentConstants.DEFAULT_SERVER_NAME); + iotServerConfigs.setDeviceOwner(AgentConstants.DEFAULT_DEVICE_OWNER); + iotServerConfigs.setDeviceId(AgentConstants.DEFAULT_DEVICE_ID); + iotServerConfigs.setDeviceName(AgentConstants.DEFAULT_DEVICE_NAME); + iotServerConfigs.setControllerContext(AgentConstants.DEVICE_CONTROLLER_API_EP); + iotServerConfigs.setHTTPS_ServerEndpoint(AgentConstants.DEFAULT_HTTPS_SERVER_EP); + iotServerConfigs.setHTTP_ServerEndpoint(AgentConstants.DEFAULT_HTTP_SERVER_EP); + iotServerConfigs.setApimGatewayEndpoint(AgentConstants.DEFAULT_APIM_GATEWAY_EP); + iotServerConfigs.setMqttBrokerEndpoint(AgentConstants.DEFAULT_MQTT_BROKER_EP); + iotServerConfigs.setXmppServerEndpoint(AgentConstants.DEFAULT_XMPP_SERVER_EP); + iotServerConfigs.setAuthMethod(AgentConstants.DEFAULT_AUTH_METHOD); + iotServerConfigs.setAuthToken(AgentConstants.DEFAULT_AUTH_TOKEN); + iotServerConfigs.setRefreshToken(AgentConstants.DEFAULT_REFRESH_TOKEN); + iotServerConfigs.setDataPushInterval(AgentConstants.DEFAULT_DATA_PUBLISH_INTERVAL); + + return iotServerConfigs; + } + + + /** + * This method constructs the URLs for each of the API Endpoints called by the device agent + * Ex: Register API, Push-Data API + * + * @throws AgentCoreOperationException if any error occurs at socket level whilst trying to + * retrieve the deviceIP of the network-interface read + * from the configs file + */ + public static void initializeServerEndPoints() { + AgentManager agentManager = AgentManager.getInstance(); + String serverSecureEndpoint = agentManager.getAgentConfigs().getHTTPS_ServerEndpoint(); + String serverUnSecureEndpoint = agentManager.getAgentConfigs().getHTTP_ServerEndpoint(); + String backEndContext = agentManager.getAgentConfigs().getControllerContext(); + + String deviceControllerAPIEndpoint = serverSecureEndpoint + backEndContext; + + String deviceEnrollmentEndpoint = + serverUnSecureEndpoint + backEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP; + agentManager.setEnrollmentEP(deviceEnrollmentEndpoint); + + String registerEndpointURL = + deviceControllerAPIEndpoint + AgentConstants.DEVICE_REGISTER_API_EP; + agentManager.setIpRegistrationEP(registerEndpointURL); + + String pushDataEndPointURL = + deviceControllerAPIEndpoint + AgentConstants.DEVICE_PUSH_TEMPERATURE_API_EP; + agentManager.setPushDataAPIEP(pushDataEndPointURL); + + log.info(AgentConstants.LOG_APPENDER + "IoT Server's Device Controller API Endpoint: " + + deviceControllerAPIEndpoint); + log.info(AgentConstants.LOG_APPENDER + "Device Enrollment EndPoint: " + + registerEndpointURL); + log.info(AgentConstants.LOG_APPENDER + "DeviceIP Registration EndPoint: " + + registerEndpointURL); + log.info(AgentConstants.LOG_APPENDER + "Push-Data API EndPoint: " + pushDataEndPointURL); + } + + + public static String prepareSecurePayLoad(String message) throws AgentCoreOperationException { + PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey(); + PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey(); + + String encryptedMsg; + try { + encryptedMsg = CommunicationUtils.encryptMessage(message, serverPublicKey); + } catch (TransportHandlerException e) { + String errorMsg = "Error occurred whilst trying to encryptMessage: [" + message + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + String signedPayload; + try { + signedPayload = CommunicationUtils.signMessage(encryptedMsg, devicePrivateKey); + } catch (TransportHandlerException e) { + String errorMsg = "Error occurred whilst trying to sign encrypted message of: [" + message + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + JSONObject jsonPayload = new JSONObject(); + jsonPayload.put(JSON_MESSAGE_KEY, encryptedMsg); + jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload); + + return jsonPayload.toString(); + } + + + public static String extractMessageFromPayload(String message) throws AgentCoreOperationException { + String actualMessage; + + PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey(); + PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey(); + + JSONObject jsonPayload = new JSONObject(message); + Object encryptedMessage = jsonPayload.get(JSON_MESSAGE_KEY); + Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY); + boolean verification; + + if (encryptedMessage != null && signedPayload != null) { + try { + verification = CommunicationUtils.verifySignature( + encryptedMessage.toString(), signedPayload.toString(), serverPublicKey); + } catch (TransportHandlerException e) { + String errorMsg = + "Error occurred whilst trying to verify signature on received message: [" + message + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + } else { + String errorMsg = "The received message is in an INVALID format. " + + "Need to be JSON - {\"Msg\":\"\", \"Sig\":\"\"}."; + throw new AgentCoreOperationException(errorMsg); + } + + try { + if (verification) { + actualMessage = CommunicationUtils.decryptMessage(encryptedMessage.toString(), devicePrivateKey); + } else { + String errorMsg = "Could not verify payload signature. The message was not signed by a valid client"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg); + } + } catch (TransportHandlerException e) { + String errorMsg = "Error occurred whilst trying to decrypt received message: [" + encryptedMessage + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return actualMessage; + } + + public static String formatMessage(String message) { + StringBuilder formattedMsg = new StringBuilder(message); + + ArrayList keyWordList = new ArrayList(); + keyWordList.add("define"); + keyWordList.add("from"); + keyWordList.add("select"); + keyWordList.add("group"); + keyWordList.add("insert"); + keyWordList.add(";"); + + + for (String keyWord : keyWordList) { + int startIndex = 0; + + while (true) { + int keyWordIndex = formattedMsg.indexOf(keyWord, startIndex); + + if (keyWordIndex == -1) { + break; + } + + if (keyWord.equals(";")) { + if (keyWordIndex != 0 && (keyWordIndex + 1) != formattedMsg.length() && + formattedMsg.charAt(keyWordIndex + 1) == ' ') { + formattedMsg.setCharAt((keyWordIndex + 1), '\n'); + } + } else { + if (keyWordIndex != 0 && formattedMsg.charAt(keyWordIndex - 1) == ' ') { + formattedMsg.setCharAt((keyWordIndex - 1), '\n'); + } + } + startIndex = keyWordIndex + 1; + } + } + return formattedMsg.toString(); + } + + public static boolean writeToFile(String content, String fileLocation) { + File file = new File(fileLocation); + + try (FileOutputStream fop = new FileOutputStream(file)) { + + // if file doesn't exists, then create it + if (!file.exists()) { + file.createNewFile(); + } + + // get the content in bytes + byte[] contentInBytes = content.getBytes(StandardCharsets.UTF_8); + + fop.write(contentInBytes); + fop.flush(); + fop.close(); + + System.out.println("Done"); + AgentManager.setUpdated(true); + return true; + + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + +} + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/enrollment/EnrollmentManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/enrollment/EnrollmentManager.java new file mode 100644 index 000000000..b6f26ad05 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/enrollment/EnrollmentManager.java @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.enrollment; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; +import org.jscep.client.Client; +import org.jscep.client.ClientException; +import org.jscep.client.EnrollmentResponse; +import org.jscep.client.verification.CertificateVerifier; +import org.jscep.client.verification.OptimisticCertificateVerifier; +import org.jscep.transaction.TransactionException; +import org.jscep.transport.response.Capabilities; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception.AgentCoreOperationException; +import sun.security.x509.X509CertImpl; + +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; + +/** + * This class controls the entire SCEP enrolment process of the client. It is a singleton for any single client which + * has the agent code running in it. The main functionality of this class includes generating a Private-Public Key + * Pair for the enrollment flow, creating the Certificate-Sign-Request using the generated Public-Key to send to the + * SEP server, Contacting the SCEP server to receive the Signed Certificate and requesting for the server's public + * key for encrypting the payloads. + * The provider for all Cryptographic functions used in this class are "BouncyCastle" and the Asymmetric-Key pair + * algorithm used is "RSA" with a key size of 2048. The signature algorithm used is "SHA1withRSA". + * This class also holds the "SCEPUrl" (Server Url read from the configs file), the Private-Public Keys of the + * client, Signed SCEP certificate and the server's public certificate. + */ + +//TODO: Need to save cert and keys to file after initial enrollment... +public class EnrollmentManager { + private static final Log log = LogFactory.getLog(EnrollmentManager.class); + private static EnrollmentManager enrollmentManager; + + private static final String KEY_PAIR_ALGORITHM = "RSA"; + private static final String PROVIDER = "BC"; + private static final String SIGNATURE_ALG = "SHA1withRSA"; + private static final int KEY_SIZE = 2048; + + // Seed to our PRNG. Make sure this is initialised randomly, NOT LIKE THIS + private static final byte[] SEED = ")(*&^%$#@!".getBytes(); + private static final int CERT_VALIDITY = 730; + + // URL of our SCEP server + private String SCEPUrl; + private PrivateKey privateKey; + private PublicKey publicKey; + private PublicKey serverPublicKey; + private X509Certificate SCEPCertificate; + + + /** + * Constructor of the EnrollmentManager. Initializes the SCEPUrl as read from the configuration file by the + * AgentManager. + */ + private EnrollmentManager() { + this.SCEPUrl = AgentManager.getInstance().getEnrollmentEP(); + } + + /** + * Method to return the current singleton instance of the EnrollmentManager. + * + * @return the current singleton instance if available and if not initializes a new instance and returns it. + */ + public static EnrollmentManager getInstance() { + if (enrollmentManager == null) { + enrollmentManager = new EnrollmentManager(); + } + return enrollmentManager; + } + + + /** + * Method to control the entire enrollment flow. This method calls the method to create the Private-Public Key + * Pair, calls the specific method to generate the Certificate-Sign-Request, creates a one time self signed + * certificate to present to the SCEP server with the initial CSR, calls the specific method to connect to the + * SCEP Server and to get the SCEP Certificate and also calls the method that requests the SCEP Server for its + * PublicKey for future payload encryption. + * + * @throws AgentCoreOperationException if the private method generateCertSignRequest() fails with an error or if + * there is an error creating a self-sign certificate to present to the + * server (whilst trying to get the CSR signed) + */ + public void beginEnrollmentFlow() throws AgentCoreOperationException { + Security.addProvider(new BouncyCastleProvider()); + + KeyPair keyPair = generateKeyPair(); + this.privateKey = keyPair.getPrivate(); + this.publicKey = keyPair.getPublic(); + + if (log.isDebugEnabled()) { + log.info(AgentConstants.LOG_APPENDER + "DevicePrivateKey:\n[\n" + privateKey + "\n]\n"); + log.info(AgentConstants.LOG_APPENDER + "DevicePublicKey:\n[\n" + publicKey + "\n]\n"); + } + + PKCS10CertificationRequest certSignRequest = generateCertSignRequest(); + + /** + * ----------------------------------------------------------------------------------------------- + * Generate an ephemeral self-signed certificate. This is needed to present to the CA in the SCEP request. + * In the future, add proper EKU and attributes in the request. The CA does NOT have to honour any of this. + * ----------------------------------------------------------------------------------------------- + */ + X500Name issuer = new X500Name("CN=Temporary Issuer"); + BigInteger serial = new BigInteger(32, new SecureRandom()); + Date fromDate = new Date(); + Date toDate = new Date(System.currentTimeMillis() + (CERT_VALIDITY * 86400000L)); + + // Build the self-signed cert using BC, sign it with our private key (self-signed) + X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuer, serial, fromDate, toDate, + certSignRequest.getSubject(), + certSignRequest.getSubjectPublicKeyInfo()); + ContentSigner sigGen; + X509Certificate tmpCert; + + try { + sigGen = new JcaContentSignerBuilder(SIGNATURE_ALG).setProvider(PROVIDER).build(keyPair.getPrivate()); + tmpCert = new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certBuilder.build(sigGen)); + } catch (OperatorCreationException e) { + String errorMsg = "Error occurred whilst creating a ContentSigner for the Temp-Self-Signed Certificate."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (CertificateException e) { + String errorMsg = "Error occurred whilst trying to create Temp-Self-Signed Certificate."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + /** + * ----------------------------------------------------------------------------------------------- + */ + + this.SCEPCertificate = getSignedCertificateFromServer(tmpCert, certSignRequest); + this.serverPublicKey = initPublicKeyOfServer(); + + if (log.isDebugEnabled()) { + log.info(AgentConstants.LOG_APPENDER + "TemporaryCertPublicKey:\n[\n" + tmpCert.getPublicKey() + "\n]\n"); + log.info(AgentConstants.LOG_APPENDER + "ServerPublicKey:\n[\n" + serverPublicKey + "\n]\n"); + } + + } + + + /** + * This method creates the Public-Private Key pair for the current client. + * + * @return the generated KeyPair object + * @throws AgentCoreOperationException when the given Security Provider does not exist or the Algorithmn used to + * generate the key pair is invalid. + */ + private KeyPair generateKeyPair() throws AgentCoreOperationException { + + // Generate key pair + KeyPairGenerator keyPairGenerator; + try { + keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM, PROVIDER); + keyPairGenerator.initialize(KEY_SIZE, new SecureRandom(SEED)); + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm [" + KEY_PAIR_ALGORITHM + "] provided for KeyPairGenerator is invalid."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (NoSuchProviderException e) { + String errorMsg = "Provider [" + PROVIDER + "] provided for KeyPairGenerator does not exist."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return keyPairGenerator.genKeyPair(); + } + + + /** + * This method creates the PKCS10 Certificate Sign Request which is to be sent to the SCEP Server using the + * generated PublicKey of the client. The certificate parameters used here are the ones from the AgentManager + * which are the values read from the configurations file. + * + * @return the PKCS10CertificationRequest object created using the client specific configs and the generated + * PublicKey + * @throws AgentCoreOperationException if an error occurs when creating a content signer to sign the CSR. + */ + private PKCS10CertificationRequest generateCertSignRequest() throws AgentCoreOperationException { + // Build the CN for the cert that's being requested. + X500NameBuilder nameBld = new X500NameBuilder(BCStyle.INSTANCE); + nameBld.addRDN(BCStyle.CN, AgentManager.getInstance().getAgentConfigs().getServerName()); + nameBld.addRDN(BCStyle.O, AgentManager.getInstance().getAgentConfigs().getDeviceOwner()); + nameBld.addRDN(BCStyle.OU, AgentManager.getInstance().getAgentConfigs().getDeviceOwner()); + nameBld.addRDN(BCStyle.UNIQUE_IDENTIFIER, AgentManager.getInstance().getAgentConfigs().getDeviceId()); + nameBld.addRDN(BCStyle.SERIALNUMBER, AgentManager.getInstance().getAgentConfigs().getDeviceId()); + X500Name principal = nameBld.build(); + + JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGNATURE_ALG).setProvider(PROVIDER); + ContentSigner contentSigner; + + try { + contentSigner = contentSignerBuilder.build(this.privateKey); + } catch (OperatorCreationException e) { + String errorMsg = "Could not create content signer with private key."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + // Generate the certificate signing request (csr = PKCS10) + PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(principal, + this.publicKey); + return reqBuilder.build(contentSigner); + } + + + /** + * This method connects to the SCEP Server to fetch the signed SCEP Certificate. + * + * @param tempCert the temporary self-signed certificate of the client required for the initial CSR + * request against the SCEP Server. + * @param certSignRequest the PKCS10 Certificate-Sign-Request that is to be sent to the SCEP Server. + * @return the SCEP-Certificate for the client signed by the SCEP-Server. + * @throws AgentCoreOperationException if the SCEPUrl is invalid or if the flow of sending the CSR and getting + * the signed certificate fails or if the signed certificate cannot be + * retrieved from the reply from the server. + */ + private X509Certificate getSignedCertificateFromServer(X509Certificate tempCert, + PKCS10CertificationRequest certSignRequest) + throws AgentCoreOperationException { + + X509Certificate signedSCEPCertificate = null; + URL url; + EnrollmentResponse enrolResponse; + CertStore certStore; + + try { + // The URL where we are going to request our cert from + url = new URL(this.SCEPUrl); + + /* // This is called when we get the certificate for our CSR signed by CA + // Implement this handler to check the CA cert in prod. We can do cert pinning here + CallbackHandler cb = new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated + methods, choose Tools | Templates. + } + };*/ + + // Implement verification of the CA cert. VERIFY the CA + CertificateVerifier ocv = new OptimisticCertificateVerifier(); + + // Instantiate our SCEP client + Client scepClient = new Client(url, ocv); + + // Submit our cert for signing. SCEP server should allow the client to specify + // the SCEP CA to issue the request against, if there are multiple CAs + enrolResponse = scepClient.enrol(tempCert, this.privateKey, certSignRequest); + + // Verify we got what we want, and just print out the cert. + certStore = enrolResponse.getCertStore(); + + for (Certificate x509Certificate : certStore.getCertificates(null)) { + if (log.isDebugEnabled()) { + log.debug(x509Certificate.toString()); + } + signedSCEPCertificate = (X509Certificate) x509Certificate; + } + + } catch (MalformedURLException ex) { + String errorMsg = "Could not create valid URL from given SCEP URI: " + SCEPUrl; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, ex); + } catch (TransactionException | ClientException e) { + String errorMsg = "Enrollment process to SCEP Server at: " + SCEPUrl + " failed."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (CertStoreException e) { + String errorMsg = "Could not retrieve [Signed-Certificate] from the response message from SCEP-Server."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return signedSCEPCertificate; + } + + + /** + * Gets the Public Key of the SCEP-Server and initializes it for later use. This method contacts the SCEP Server + * and fetches its CA Cert and extracts the Public Key of the server from the received reply. + * + * @return the public key of the SCEP Server which is to be used to encrypt pyloads. + * @throws AgentCoreOperationException if the SCEPUrl is invalid or if the flow of sending the CSR and getting + * the signed certificate fails or if the signed certificate cannot be + * retrieved from the reply from the server. + */ + private PublicKey initPublicKeyOfServer() throws AgentCoreOperationException { + URL url; + CertStore certStore; + PublicKey serverCertPublicKey = null; + + try { + // The URL where we are going to request our cert from + url = new URL(this.SCEPUrl); + + /* // This is called when we get the certificate for our CSR signed by CA + // Implement this handler to check the CA cert in prod. We can do cert pinning here + CallbackHandler cb = new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated + methods, choose Tools | Templates. + } + };*/ + + // Implement verification of the CA cert. VERIFY the CA + CertificateVerifier ocv = new OptimisticCertificateVerifier(); + + // Instantiate our SCEP client + Client scepClient = new Client(url, ocv); + + // Get the CA capabilities. Should return SHA1withRSA for strongest hash and sig. Returns MD5. + if (log.isDebugEnabled()) { + Capabilities cap = scepClient.getCaCapabilities(); + log.debug(String.format( + "\nStrongestCipher: %s,\nStrongestMessageDigest: %s,\nStrongestSignatureAlgorithm: %s," + + "\nIsRenewalSupported: %s,\nIsRolloverSupported: %s", + cap.getStrongestCipher(), cap.getStrongestMessageDigest(), cap.getStrongestSignatureAlgorithm(), + cap.isRenewalSupported(), cap.isRolloverSupported())); + } + + certStore = scepClient.getCaCertificate(); + + for (Certificate cert : certStore.getCertificates(null)) { + if (cert instanceof X509Certificate) { + if (log.isDebugEnabled()) { + log.debug(((X509Certificate) cert).getIssuerDN().getName()); + } + + //TODO: Need to identify the correct certificate. + // I have chosen the CA cert based on its BasicConstraint criticality being set to "true" + if (((X509CertImpl) cert).getBasicConstraintsExtension().isCritical()) { + serverCertPublicKey = cert.getPublicKey(); + } + } + } + + } catch (MalformedURLException ex) { + String errorMsg = "Could not create valid URL from given SCEP URI: " + SCEPUrl; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, ex); + } catch (ClientException e) { + String errorMsg = "Could not retrieve [Server-Certificate] from the SCEP-Server."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (CertStoreException e) { + String errorMsg = "Could not retrieve [Server-Certificates] from the response message from SCEP-Server."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return serverCertPublicKey; + } + + + /** + * Gets the Public-Key of the client. + * + * @return the public key of the client. + */ + public PublicKey getPublicKey() { + return publicKey; + } + + /** + * Gets the Private-Key of the client. + * + * @return the private key of the client. + */ + public PrivateKey getPrivateKey() { + return privateKey; + } + + /** + * Gets the SCEP-Certificate of the client. + * + * @return the SCEP Certificate of the client. + */ + public X509Certificate getSCEPCertificate() { + return SCEPCertificate; + } + + /** + * Gets the Public-Key of the Server. + * + * @return the pubic key of the server. + */ + public PublicKey getServerPublicKey() { + return serverPublicKey; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/exception/AgentCoreOperationException.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/exception/AgentCoreOperationException.java new file mode 100644 index 000000000..7aa102042 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/exception/AgentCoreOperationException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.exception; + + +public class AgentCoreOperationException extends Exception { + private static final long serialVersionUID = 2736466230451105710L; + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public AgentCoreOperationException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public AgentCoreOperationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public AgentCoreOperationException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public AgentCoreOperationException() { + super(); + } + + public AgentCoreOperationException(Throwable cause) { + super(cause); + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/sidhdhi/SidhdhiQuery.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/sidhdhi/SidhdhiQuery.java new file mode 100644 index 000000000..94e6bd525 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/sidhdhi/SidhdhiQuery.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.sidhdhi; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentUtilOperations; +import org.wso2.siddhi.core.SiddhiManager; +import org.wso2.siddhi.core.event.Event; +import org.wso2.siddhi.core.stream.input.InputHandler; +import org.wso2.siddhi.core.stream.output.StreamCallback; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * This class reads the humidity reading and injects values + * to the siddhiEngine for processing on a routine basis + * also if the siddhiquery is updated the class takes + * care of re-initializing same. + */ +public class SidhdhiQuery implements Runnable { + private static final Log log = LogFactory.getLog(SidhdhiQuery.class); + public static final String sidhdhiQueryPath = AgentManager.getInstance().getRootPath() + AgentConstants.CEP_FILE_NAME; + + //Bam data push client + private static SiddhiManager siddhiManager = new SiddhiManager(); + + public static SiddhiManager getSiddhiManager() { + return siddhiManager; + } + + public static void setSiddhiManager(SiddhiManager siddhiManager) { + SidhdhiQuery.siddhiManager = siddhiManager; + } + + public void run() { + + //Start the execution plan with pre-defined or previously persisted Siddhi query + File f = new File(sidhdhiQueryPath); + + if (!f.exists()) { + AgentUtilOperations.writeToFile(AgentConstants.CEP_QUERY, sidhdhiQueryPath); + } + + StartExecutionPlan startExecutionPlan = new StartExecutionPlan().invoke(); + + while (true) { + + //Check if there is new policy update available + if (AgentManager.isUpdated()) { + System.out.print("### Policy Update Detected!"); + //Restart execution plan with new query + restartSiddhi(); + startExecutionPlan = new StartExecutionPlan().invoke(); + } + InputHandler inputHandler = startExecutionPlan.getInputHandler(); + + //Sending events to Siddhi + try { + int humidityReading = AgentManager.getInstance().getTemperature(); + inputHandler.send(new Object[]{"FIRE_1", humidityReading}); + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + break; + } + } + } + + /** + * Re-Initialize SiddhiManager + */ + private void restartSiddhi() { + siddhiManager.shutdown(); + siddhiManager = new SiddhiManager(); + } + + + /** + * Read content from a given file and return as a string + * + * @param path + * @param encoding + * @return + */ + public static String readFile(String path, Charset encoding) { + byte[] encoded = new byte[0]; + try { + encoded = Files.readAllBytes(Paths.get(path)); + } catch (IOException e) { + log.error("Error reading Sidhdhi query from file."); + } + return new String(encoded, encoding); + } + + + /** + * Read humidity data from API URL + * + * @param humidityAPIUrl + * @return + */ + private String readHumidityData(String humidityAPIUrl) { + HttpClient client = new DefaultHttpClient(); + HttpGet request = new HttpGet(humidityAPIUrl); + String responseStr = null; + try { + HttpResponse response = client.execute(request); + log.debug("Response Code : " + response); + InputStream input = response.getEntity().getContent(); + BufferedReader br = new BufferedReader(new InputStreamReader(input, "UTF-8")); + responseStr = String.valueOf(br.readLine()); + br.close(); + + } catch (IOException e) { + //log.error("Exception encountered while trying to make get request."); + log.error("Error while reading humidity reading from file!"); + return responseStr; + } + return responseStr; + } + + /** + * Initialize SiddhiExecution plan + */ + private static class StartExecutionPlan { + private InputHandler inputHandler; + + public InputHandler getInputHandler() { + return inputHandler; + } + + public StartExecutionPlan invoke() { + String executionPlan; + + executionPlan = readFile(sidhdhiQueryPath, StandardCharsets.UTF_8); + + //Generating runtime + siddhiManager.addExecutionPlan(executionPlan); + + siddhiManager.addCallback("bulbOnStream", new StreamCallback() { + @Override + public void receive(Event[] events) { + System.out.println("Bulb on Event Fired!"); + if (events.length > 0) { + if (!AgentManager.getInstance().isAlarmOn()) { + AgentManager.getInstance().changeAlarmStatus(true); + System.out.println("#### Performed HTTP call! ON."); + } + } + } + }); + + siddhiManager.addCallback("bulbOffStream", new StreamCallback() { + @Override + public void receive(Event[] inEvents) { + System.out.println("Bulb off Event Fired"); + if (AgentManager.getInstance().isAlarmOn()) { + AgentManager.getInstance().changeAlarmStatus(false); + System.out.println("#### Performed HTTP call! OFF."); + } + } + + }); + + //Retrieving InputHandler to push events into Siddhi + inputHandler = siddhiManager.getInputHandler("fireAlarmEventStream"); + + //Starting event processing + System.out.println("Execution Plan Started!"); + return this; + } + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/CommunicationUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/CommunicationUtils.java new file mode 100644 index 000000000..e6e16ba52 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/CommunicationUtils.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; + +/** + * This is a utility class which contains methods common to the communication process of a client and the server. The + * methods include encryption/decryption of payloads and signing/verification of payloads received and to be sent. + */ +public class CommunicationUtils { + private static final Log log = LogFactory.getLog(TransportUtils.class); + + // The Signature Algorithm used. + private static final String SIGNATURE_ALG = "SHA1withRSA"; + // The Encryption Algorithm and the Padding used. + private static final String CIPHER_PADDING = "RSA/ECB/PKCS1Padding"; + + + /** + * Encrypts the message with the key that's passed in. + * + * @param message the message to be encrypted. + * @param encryptionKey the key to use for the encryption of the message. + * @return the encrypted message in String format. + * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding + * issues, encryption key being invalid or the algorithm used is unrecognizable. + */ + public static String encryptMessage(String message, Key encryptionKey) throws TransportHandlerException { + Cipher encrypter; + byte[] cipherData; + + try { + encrypter = Cipher.getInstance(CIPHER_PADDING); + encrypter.init(Cipher.ENCRYPT_MODE, encryptionKey); + cipherData = encrypter.doFinal(message.getBytes(StandardCharsets.UTF_8)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + encryptionKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return Base64.encodeBase64String(cipherData); + } + +///TODO:: Exception needs to change according to the common package + + /** + * Signed a given message using the PrivateKey that's passes in. + * + * @param message the message to be signed. Ideally some encrypted payload. + * @param signatureKey the PrivateKey with which the message is to be signed. + * @return the Base64Encoded String of the signed payload. + * @throws TransportHandlerException if some error occurs with the signing process which may be related to the + * signature algorithm used or the key used for signing. + */ + public static String signMessage(String message, PrivateKey signatureKey) throws TransportHandlerException { + + Signature signature; + String signedEncodedString; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initSign(signatureKey); + signature.update(Base64.decodeBase64(message)); + + byte[] signatureBytes = signature.sign(); + signedEncodedString = Base64.encodeBase64String(signatureBytes); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = + "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + signatureKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return signedEncodedString; + } + + + /** + * Verifies some signed-data against the a Public-Key to ensure that it was produced by the holder of the + * corresponding Private Key. + * + * @param data the actual payoad which was signed by some Private Key. + * @param signedData the signed data produced by signing the payload using a Private Key. + * @param verificationKey the corresponding Public Key which is an exact pair of the Private-Key with we expect + * the data to be signed by. + * @return true if the signed data verifies to be signed by the corresponding Private Key. + * @throws TransportHandlerException if some error occurs with the verification process which may be related to + * the signature algorithm used or the key used for signing. + */ + public static boolean verifySignature(String data, String signedData, PublicKey verificationKey) + throws TransportHandlerException { + + Signature signature; + boolean verified; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initVerify(verificationKey); + signature.update(Base64.decodeBase64(data)); + + verified = signature.verify(Base64.decodeBase64(signedData)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = + "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + verificationKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return verified; + } + + + /** + * Encrypts the message with the key that's passed in. + * + * @param encryptedMessage the encrypted message that is supposed to be decrypted. + * @param decryptKey the key to use in the decryption process. + * @return the decrypted message in String format. + * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding + * issues, encryption key being invalid or the algorithm used is unrecognizable. + */ + public static String decryptMessage(String encryptedMessage, Key decryptKey) throws TransportHandlerException { + + Cipher decrypter; + String decryptedMessage; + + try { + + decrypter = Cipher.getInstance(CIPHER_PADDING); + decrypter.init(Cipher.DECRYPT_MODE, decryptKey); + decryptedMessage = new String(decrypter.doFinal(Base64.decodeBase64(encryptedMessage)), + StandardCharsets.UTF_8); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + decryptKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return decryptedMessage; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandler.java new file mode 100644 index 000000000..8034f66e2 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport; + +/** + * This interface consists of the core functionality related to the transport between any device and the server. The + * interface is an abstraction, regardless of the underlying protocol used for the transport. Implementation of this + * interface by any class that caters a specific protocol (ex: HTTP, XMPP, MQTT, CoAP) would ideally have methods + * specific to the protocol used for communication and thees methods that implement the logic related to the devices + * using the protocol. + * + * @param a message type specific to the protocol implemented + */ +public interface TransportHandler { + int DEFAULT_TIMEOUT_INTERVAL = 5000; // millis ~ 10 sec + + void connect(); + + boolean isConnected(); + + //TODO:: Any errors needs to be thrown ahead + void processIncomingMessage(T message, String... messageParams); + + void processIncomingMessage(); + + void publishDeviceData(String... publishData); + + void publishDeviceData(); + + void disconnect(); +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandlerException.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandlerException.java new file mode 100644 index 000000000..aeccc0fbc --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportHandlerException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport; + +public class TransportHandlerException extends Exception { + private static final long serialVersionUID = 2736466230451105440L; + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public TransportHandlerException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public TransportHandlerException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public TransportHandlerException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public TransportHandlerException() { + super(); + } + + public TransportHandlerException(Throwable cause) { + super(cause); + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportUtils.java new file mode 100644 index 000000000..a9b6676a3 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/TransportUtils.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.DatagramSocket; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.SocketException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class TransportUtils { + private static final Log log = LogFactory.getLog(TransportUtils.class); + + public static final int MIN_PORT_NUMBER = 9000; + public static final int MAX_PORT_NUMBER = 11000; + + /** + * Given a server endpoint as a String, this method splits it into Protocol, Host and Port + * + * @param ipString a network endpoint in the format - '://:' + * @return a map with keys "Protocol", "Host" & "Port" for the related values from the ipString + * @throws TransportHandlerException + */ + public static Map getHostAndPort(String ipString) + throws TransportHandlerException { + Map ipPortMap = new HashMap(); + String[] ipPortArray = ipString.split(":"); + + if (ipPortArray.length != 3) { + String errorMsg = + "The IP String - '" + ipString + + "' is invalid. It needs to be in format '://:'."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg); + } + + ipPortMap.put("Protocol", ipPortArray[0]); + ipPortMap.put("Host", ipPortArray[1].replace(File.separator, "")); + ipPortMap.put("Port", ipPortArray[2]); + return ipPortMap; + } + + /** + * This method validates whether a specific IP Address is of IPv4 type + * + * @param ipAddress the IP Address which needs to be validated + * @return true if it is of IPv4 type and false otherwise + */ + public static boolean validateIPv4(String ipAddress) { + try { + if (ipAddress == null || ipAddress.isEmpty()) { + return false; + } + + String[] parts = ipAddress.split("\\."); + if (parts.length != 4) { + return false; + } + + for (String s : parts) { + int i = Integer.parseInt(s); + if ((i < 0) || (i > 255)) { + return false; + } + } + return !ipAddress.endsWith("."); + + } catch (NumberFormatException nfe) { + log.warn("The IP Address: " + ipAddress + " could not " + + "be validated against IPv4-style"); + return false; + } + } + + + public static Map getInterfaceIPMap() throws TransportHandlerException { + + Map interfaceToIPMap = new HashMap(); + Enumeration networkInterfaces; + String networkInterfaceName = ""; + String ipAddress; + + try { + networkInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException exception) { + String errorMsg = + "Error encountered whilst trying to get the list of network-interfaces"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + try { + for (; networkInterfaces.hasMoreElements(); ) { + networkInterfaceName = networkInterfaces.nextElement().getName(); + + if (log.isDebugEnabled()) { + log.debug("Network Interface: " + networkInterfaceName); + log.debug("------------------------------------------"); + } + + Enumeration interfaceIPAddresses = NetworkInterface.getByName( + networkInterfaceName).getInetAddresses(); + + for (; interfaceIPAddresses.hasMoreElements(); ) { + ipAddress = interfaceIPAddresses.nextElement().getHostAddress(); + + if (log.isDebugEnabled()) { + log.debug("IP Address: " + ipAddress); + } + + if (TransportUtils.validateIPv4(ipAddress)) { + interfaceToIPMap.put(networkInterfaceName, ipAddress); + } + } + + if (log.isDebugEnabled()) { + log.debug("------------------------------------------"); + } + } + } catch (SocketException exception) { + String errorMsg = + "Error encountered whilst trying to get the IP Addresses of the network " + + "interface: " + networkInterfaceName; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + return interfaceToIPMap; + } + + + /** + * Attempts to find a free port between the MIN_PORT_NUMBER(9000) and MAX_PORT_NUMBER(11000). + * Tries 'RANDOMLY picked' port numbers between this range up-until "randomAttempts" number of + * times. If still fails, then tries each port in descending order from the MAX_PORT_NUMBER + * whilst skipping already attempted ones via random selection. + * + * @param randomAttempts no of times to TEST port numbers picked randomly over the given range + * @return an available/free port + */ + public static synchronized int getAvailablePort(int randomAttempts) { + ArrayList failedPorts = new ArrayList(randomAttempts); + + Random randomNum = new Random(); + int randomPort = MAX_PORT_NUMBER; + + while (randomAttempts > 0) { + randomPort = randomNum.nextInt(MAX_PORT_NUMBER - MIN_PORT_NUMBER) + MIN_PORT_NUMBER; + + if (checkIfPortAvailable(randomPort)) { + return randomPort; + } + failedPorts.add(randomPort); + randomAttempts--; + } + + randomPort = MAX_PORT_NUMBER; + + while (true) { + if (!failedPorts.contains(randomPort) && checkIfPortAvailable(randomPort)) { + return randomPort; + } + randomPort--; + } + } + + + private static boolean checkIfPortAvailable(int port) { + ServerSocket tcpSocket = null; + DatagramSocket udpSocket = null; + + try { + tcpSocket = new ServerSocket(port); + tcpSocket.setReuseAddress(true); + + udpSocket = new DatagramSocket(port); + udpSocket.setReuseAddress(true); + return true; + } catch (IOException ex) { + // denotes the port is in use + } finally { + if (tcpSocket != null) { + try { + tcpSocket.close(); + } catch (IOException e) { + /* not to be thrown */ + } + } + + if (udpSocket != null) { + udpSocket.close(); + } + } + + return false; + } + + + /** + * This is a utility method that creates and returns a HTTP connection object. + * + * @param urlString the URL pattern to which the connection needs to be created + * @return an HTTPConnection object which cn be used to send HTTP requests + * @throws TransportHandlerException if errors occur when creating the HTTP connection with + * the given URL string + */ + public static HttpURLConnection getHttpConnection(String urlString) throws + TransportHandlerException { + URL connectionUrl; + HttpURLConnection httpConnection; + + try { + connectionUrl = new URL(urlString); + httpConnection = (HttpURLConnection) connectionUrl.openConnection(); + } catch (MalformedURLException e) { + String errorMsg = "Error occured whilst trying to form HTTP-URL from string: " + urlString; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IOException exception) { + String errorMsg = "Error occured whilst trying to open a connection to: " + urlString; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + return httpConnection; + } + + /** + * This is a utility method that reads and returns the response from a HTTP connection + * + * @param httpConnection the connection from which a response is expected + * @return the response (as a string) from the given HTTP connection + * @throws TransportHandlerException if any errors occur whilst reading the response from + * the connection stream + */ + public static String readResponseFromHttpRequest(HttpURLConnection httpConnection) + throws TransportHandlerException { + BufferedReader bufferedReader; + try { + bufferedReader = new BufferedReader(new InputStreamReader( + httpConnection.getInputStream(), StandardCharsets.UTF_8)); + } catch (IOException exception) { + String errorMsg = "There is an issue with connecting the reader to the input stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + String responseLine; + StringBuilder completeResponse = new StringBuilder(); + + try { + while ((responseLine = bufferedReader.readLine()) != null) { + completeResponse.append(responseLine); + } + } catch (IOException exception) { + String errorMsg = "Error occured whilst trying read from the connection stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + try { + bufferedReader.close(); + } catch (IOException exception) { + log.error( + "Could not succesfully close the bufferedReader to the connection at: " + httpConnection.getURL()); + } + return completeResponse.toString(); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/http/HTTPTransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/http/HTTPTransportHandler.java new file mode 100644 index 000000000..6abee0b09 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/http/HTTPTransportHandler.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.http; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.server.Server; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportUtils; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + */ +public abstract class HTTPTransportHandler implements TransportHandler { + private static final Log log = LogFactory.getLog(HTTPTransportHandler.class); + + protected Server server; + protected int port; + protected int timeoutInterval; + + protected HTTPTransportHandler() { + this.port = TransportUtils.getAvailablePort(10); + this.server = new Server(port); + timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + } + + protected HTTPTransportHandler(int port) { + this.port = port; + this.server = new Server(this.port); + timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + } + + protected HTTPTransportHandler(int port, int timeoutInterval) { + this.port = port; + this.server = new Server(this.port); + this.timeoutInterval = timeoutInterval; + } + + public void setTimeoutInterval(int timeoutInterval) { + this.timeoutInterval = timeoutInterval; + } + + /** + * Checks whether the HTTP server is up and listening for incoming requests. + * + * @return true if the server is up & listening for requests, else false. + */ + public boolean isConnected() { + return server.isStarted(); + } + + + protected void incrementPort() { + this.port = this.port + 1; + server = new Server(port); + } + + /** + * Shuts-down the HTTP Server. + */ + public void closeConnection() throws Exception { + if (server != null && isConnected()) { + server.stop(); + } + } + + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/mqtt/MQTTTransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/mqtt/MQTTTransportHandler.java new file mode 100644 index 000000000..d4626f6df --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/mqtt/MQTTTransportHandler.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.mqtt; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + *

      + * This class contains the Device-Management specific implementation for all the MQTT functionality. This includes + * connecting to a MQTT Broker & subscribing to the appropriate MQTT-topic, action plan upon losing connection or + * successfully delivering a message to the broker and processing incoming messages. Makes use of the 'Paho-MQTT' + * library provided by Eclipse Org. + */ +public abstract class MQTTTransportHandler + implements MqttCallback, TransportHandler { + private static final Log log = LogFactory.getLog(MQTTTransportHandler.class); + + public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0; + + private MqttClient client; + private String clientId; + private MqttConnectOptions options; + private String clientWillTopic; + + protected String mqttBrokerEndPoint; + protected int timeoutInterval; + protected String subscribeTopic; + + /** + * Constructor for the MQTTTransportHandler which takes in the owner, type of the device + * and the MQTT Broker URL and the topic to subscribe. + * + * @param deviceOwner the owner of the device. + * @param deviceType the CDMF Device-Type of the device. + * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint. + * @param subscribeTopic the MQTT topic to which the client is to be subscribed + */ + protected MQTTTransportHandler(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, + String subscribeTopic) { + this.clientId = deviceOwner + ":" + deviceType; + this.subscribeTopic = subscribeTopic; + this.clientWillTopic = deviceType + File.separator + "disconnection"; + this.mqttBrokerEndPoint = mqttBrokerEndPoint; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + this.initSubscriber(); + } + + /** + * Constructor for the MQTTTransportHandler which takes in the owner, type of the device + * and the MQTT Broker URL and the topic to subscribe. Additionally this constructor takes in + * the reconnection-time interval between successive attempts to connect to the broker. + * + * @param deviceOwner the owner of the device. + * @param deviceType the CDMF Device-Type of the device. + * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint. + * @param subscribeTopic the MQTT topic to which the client is to be subscribed + * @param intervalInMillis the time interval in MILLI-SECONDS between successive + * attempts to connect to the broker. + */ + protected MQTTTransportHandler(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic, + int intervalInMillis) { + this.clientId = deviceOwner + ":" + deviceType; + this.subscribeTopic = subscribeTopic; + //TODO:: Use constant strings + this.clientWillTopic = deviceType + File.separator + "disconnection"; + this.mqttBrokerEndPoint = mqttBrokerEndPoint; + this.timeoutInterval = intervalInMillis; + this.initSubscriber(); + } + + public void setTimeoutInterval(int timeoutInterval) { + this.timeoutInterval = timeoutInterval; + } + + /** + * Initializes the MQTT-Client. Creates a client using the given MQTT-broker endpoint and the + * clientId (which is constructed by a concatenation of [deviceOwner]:[deviceType]). Also sets + * the client's options parameter with the clientWillTopic (in-case of connection failure) and + * other info. Also sets the call-back this current class. + */ + private void initSubscriber() { + try { + client = new MqttClient(this.mqttBrokerEndPoint, clientId, null); + //TODO:: Need to check for debug + log.info("MQTT subscriber was created with ClientID : " + clientId); + } catch (MqttException ex) { + //TODO:: Remove unnecessary formatting and print exception + String errorMsg = "MQTT Client Error\n" + "\tReason: " + ex.getReasonCode() + + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + + "\n\tException: " + ex; + log.error(errorMsg); + //TODO:: Throw the error out + } + + options = new MqttConnectOptions(); + options.setCleanSession(false); + //TODO:: Use constant strings + options.setWill(clientWillTopic, "Connection-Lost".getBytes(StandardCharsets.UTF_8), 2, + true); + client.setCallback(this); + } + + /** + * Checks whether the connection to the MQTT-Broker persists. + * + * @return true if the client is connected to the MQTT-Broker, else false. + */ + @Override + public boolean isConnected() { + return client.isConnected(); + } + + + /** + * Connects to the MQTT-Broker and if successfully established connection. + * + * @throws TransportHandlerException in the event of 'Connecting to' the MQTT broker fails. + */ + protected void connectToQueue() throws TransportHandlerException { + try { + client.connect(options); + + if (log.isDebugEnabled()) { + log.debug("Subscriber connected to queue at: " + this.mqttBrokerEndPoint); + } + } catch (MqttSecurityException ex) { + String errorMsg = "MQTT Security Exception when connecting to queue\n" + "\tReason: " + + " " + + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + + ex.getCause() + "\n\tException: " + ex; + //TODO:: Compulsory log of errors and remove formatted error + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + throw new TransportHandlerException(errorMsg, ex); + + } catch (MqttException ex) { + //TODO:: Compulsory log of errors and remove formatted error + String errorMsg = "MQTT Exception when connecting to queue\n" + "\tReason: " + + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + + ex.getCause() + "\n\tException: " + ex; + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + throw new TransportHandlerException(errorMsg, ex); + } + } + + /** + * Subscribes to the MQTT-Topic specific to this MQTT Client. (The MQTT-Topic specific to the + * device is taken in as a constructor parameter of this class) . + * + * @throws TransportHandlerException in the event of 'Subscribing to' the MQTT broker + * fails. + */ + protected void subscribeToQueue() throws TransportHandlerException { + try { + //TODO:: QoS Level take it from a variable + client.subscribe(subscribeTopic, 0); + log.info("Subscriber '" + clientId + "' subscribed to topic: " + subscribeTopic); + } catch (MqttException ex) { + //TODO:: Compulsory log of errors and remove formatted error + String errorMsg = "MQTT Exception when trying to subscribe to topic: " + + subscribeTopic + "\n\tReason: " + ex.getReasonCode() + + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + + "\n\tException: " + ex; + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + + throw new TransportHandlerException(errorMsg, ex); + } + } + + + /** + * This method is used to publish reply-messages for the control signals received. + * Invocation of this method calls its overloaded-method with a QoS equal to that of the + * default value. + * + * @param topic the topic to which the reply message is to be published. + * @param payLoad the reply-message (payload) of the MQTT publish action. + */ + protected void publishToQueue(String topic, String payLoad) + throws TransportHandlerException { + publishToQueue(topic, payLoad, DEFAULT_MQTT_QUALITY_OF_SERVICE, false); + } + + /** + * This is an overloaded method that publishes MQTT reply-messages for control signals + * received form the IoT-Server. + * + * @param topic the topic to which the reply message is to be published + * @param payLoad the reply-message (payload) of the MQTT publish action. + * @param qos the Quality-of-Service of the current publish action. + * Could be 0(At-most once), 1(At-least once) or 2(Exactly once) + */ + protected void publishToQueue(String topic, String payLoad, int qos, boolean retained) + throws TransportHandlerException { + try { + client.publish(topic, payLoad.getBytes(StandardCharsets.UTF_8), qos, retained); + if (log.isDebugEnabled()) { + log.debug("Message: " + payLoad + " to MQTT topic [" + topic + + "] published successfully"); + } + } catch (MqttException ex) { + String errorMsg = + "MQTT Client Error" + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " + + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + + protected void publishToQueue(String topic, MqttMessage message) + throws TransportHandlerException { + try { + client.publish(topic, message); + if (log.isDebugEnabled()) { + log.debug("Message: " + message.toString() + " to MQTT topic [" + topic + + "] published successfully"); + } + } catch (MqttException ex) { + //TODO:: Compulsory log of errors and remove formatted error + String errorMsg = + "MQTT Client Error" + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " + + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + + /** + * Callback method which is triggered once the MQTT client losers its connection to the broker. + * Spawns a new thread that executes necessary actions to try and reconnect to the endpoint. + * + * @param throwable a Throwable Object containing the details as to why the failure occurred. + */ + @Override + public void connectionLost(Throwable throwable) { + log.warn("Lost Connection for client: " + this.clientId + + " to " + this.mqttBrokerEndPoint + ".\nThis was due to - " + + throwable.getMessage()); + + Thread reconnectThread = new Thread() { + public void run() { + connect(); + } + }; + reconnectThread.setDaemon(true); + reconnectThread.start(); + } + + /** + * Callback method which is triggered upon receiving a MQTT Message from the broker. Spawns a + * new thread that executes any actions to be taken with the received message. + * + * @param topic the MQTT-Topic to which the received message was published to and the + * client was subscribed to. + * @param mqttMessage the actual MQTT-Message that was received from the broker. + */ + @Override + public void messageArrived(final String topic, final MqttMessage mqttMessage) { + if (log.isDebugEnabled()) { + log.info("Got an MQTT message '" + mqttMessage.toString() + "' for topic '" + topic + "'."); + } + + Thread messageProcessorThread = new Thread() { + public void run() { + processIncomingMessage(mqttMessage, topic); + } + }; + messageProcessorThread.setDaemon(true); + messageProcessorThread.start(); + } + + /** + * Callback method which gets triggered upon successful completion of a message delivery to + * the broker. + * + * @param iMqttDeliveryToken the MQTT-DeliveryToken which includes the details about the + * specific message delivery. + */ + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + String message = ""; + try { + message = iMqttDeliveryToken.getMessage().toString(); + } catch (MqttException e) { + //TODO:: Throw errors + log.error( + "Error occurred whilst trying to read the message from the MQTT delivery " + + "token."); + } + String topic = iMqttDeliveryToken.getTopics()[0]; + String client = iMqttDeliveryToken.getClient().getClientId(); + + if (log.isDebugEnabled()) { + log.debug("Message - '" + message + "' of client [" + client + "] for the topic (" + + topic + ") was delivered successfully."); + } + } + + /** + * Closes the connection to the MQTT Broker. + */ + public void closeConnection() throws MqttException { + if (client != null && isConnected()) { + client.disconnect(); + } + } +} + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/xmpp/XMPPTransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/xmpp/XMPPTransportHandler.java new file mode 100644 index 000000000..ba8320c7c --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/transport/xmpp/XMPPTransportHandler.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.xmpp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.ConnectionConfiguration; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.AndFilter; +import org.jivesoftware.smack.filter.FromContainsFilter; +import org.jivesoftware.smack.filter.OrFilter; +import org.jivesoftware.smack.filter.PacketFilter; +import org.jivesoftware.smack.filter.PacketTypeFilter; +import org.jivesoftware.smack.filter.ToContainsFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.transport.TransportHandlerException; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + *

      + * This class contains the IoT-Server specific implementation for all the XMPP functionality. This includes + * connecting to a XMPP Server & Login-In using the device's/server's XMPP-Account, Setting listeners and filters on + * incoming XMPP messages and Sending XMPP replies for messages received. Makes use of the 'Smack-XMPP' library + * provided by jivesoftware/igniterealtime. + */ +public abstract class XMPPTransportHandler implements TransportHandler { + private static final Log log = LogFactory.getLog(XMPPTransportHandler.class); + + protected String server; + protected int timeoutInterval; // millis + + //TODO:: Shouldnt be hard-coded. Need to be read from configs + private static final int DEFAULT_XMPP_PORT = 5222; + private XMPPConnection connection; + private int port; + private ConnectionConfiguration config; + private PacketFilter filter; + private PacketListener listener; + + + /** + * Constructor for XMPPTransportHandler passing only the server-IP. + * + * @param server the IP of the XMPP server. + */ + protected XMPPTransportHandler(String server) { + this.server = server; + this.port = DEFAULT_XMPP_PORT; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + initXMPPClient(); + } + + /** + * Constructor for XMPPTransportHandler passing server-IP and the XMPP-port. + * + * @param server the IP of the XMPP server. + * @param port the XMPP server's port to connect to. (default - 5222) + */ + protected XMPPTransportHandler(String server, int port) { + this.server = server; + this.port = port; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + initXMPPClient(); + } + + /** + * Constructor for XMPPTransportHandler passing server-IP, the XMPP-port and the + * timeoutInterval used by listeners to the server and for reconnection schedules. + * + * @param server the IP of the XMPP server. + * @param port the XMPP server's port to connect to. (default - 5222) + * @param timeoutInterval the timeout interval to use for the connection and reconnection + */ + protected XMPPTransportHandler(String server, int port, int timeoutInterval) { + this.server = server; + this.port = port; + this.timeoutInterval = timeoutInterval; + initXMPPClient(); + } + + /** + * Sets the client's time-out-limit whilst waiting for XMPP-replies from server. + * + * @param millis the time in millis to be set as the time-out-limit whilst waiting for a + * XMPP-reply. + */ + public void setTimeoutInterval(int millis) { + this.timeoutInterval = millis; + } + + /** + * Checks whether the connection to the XMPP-Server persists. + * + * @return true if the client is connected to the XMPP-Server, else false. + */ + @Override + public boolean isConnected() { + return connection.isConnected(); + } + + /** + * Initializes the XMPP Client. Sets the time-out-limit whilst waiting for XMPP-replies from + * server. Sets the XMPP configurations to connect to the server and creates the + * XMPPConnection object used for connecting and Logging-In. + */ + private void initXMPPClient() { + log.info(String.format("Initializing connection to XMPP Server at %1$s via port " + + "%2$d.", server, port)); + SmackConfiguration.setPacketReplyTimeout(timeoutInterval); + config = new ConnectionConfiguration(server, port); +// TODO:: Need to enable SASL-Authentication appropriately + config.setSASLAuthenticationEnabled(false); + config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled); + connection = new XMPPConnection(config); + } + +//TODO:: Re-check all exception handling + + /** + * Connects to the XMPP-Server and if attempt unsuccessful, then throws exception. + * + * @throws TransportHandlerException in the event of 'Connecting to' the XMPP server fails. + */ + protected void connectToServer() throws TransportHandlerException { + try { + connection.connect(); + log.info(String.format("Connection to XMPP Server at %1$s established successfully......", server)); + + } catch (XMPPException xmppExcepion) { + String errorMsg = "Connection attempt to the XMPP Server at " + server + " via port " + port + " failed."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, xmppExcepion); + } + } + + /** + * If successfully established connection, then tries to Log in using the device's XMPP + * Account credentials. + * + * @param username the username of the device's XMPP-Account. + * @param password the password of the device's XMPP-Account. + * @param resource the resource the resource, specific to the XMPP-Account to which the login + * is made to + * @throws TransportHandlerException in the event of 'Logging into' the XMPP server fails. + */ + protected void loginToServer(String username, String password, String resource) + throws TransportHandlerException { + if (isConnected()) { + try { + if (resource == null) { + connection.login(username, password); + log.info(String.format("Logged into XMPP Server at %1$s as user %2$s......", server, username)); + } else { + connection.login(username, password, resource); + log.info(String.format("Logged into XMPP Server at %1$s as user %2$s on resource %3$s......", + server, username, resource)); + } + } catch (XMPPException xmppException) { + String errorMsg = + "Login attempt to the XMPP Server at " + server + " with username - " + username + " failed."; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, xmppException); + } + } else { + String errorMsg = "Not connected to XMPP-Server to attempt Login. Please 'connectToServer' before Login"; + throw new TransportHandlerException(errorMsg); + } + } + + + /** + * Sets a filter for all the incoming XMPP-Messages on the Sender's JID (XMPP-Account ID). + * Also creates a listener for the incoming messages and connects the listener to the + * XMPPConnection alongside the set filter. + * + * @param senderJID the JID (XMPP-Account ID of the sender) to which the filter is to be set. + */ + protected void setFilterOnSender(String senderJID) { + filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter( + senderJID)); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + processIncomingMessage(xmppMessage); + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + + connection.addPacketListener(listener, filter); + } + + + /** + * Sets a filter for all the incoming XMPP-Messages on the Receiver's JID (XMPP-Account ID). + * Also creates a listener for the incoming messages and connects the listener to the + * XMPPConnection alongside the set filter. + * + * @param receiverJID the JID (XMPP-Account ID of the receiver) to which the filter is to be + * set. + */ + protected void setFilterOnReceiver(String receiverJID) { + filter = new AndFilter(new PacketTypeFilter(Message.class), new ToContainsFilter( + receiverJID)); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + processIncomingMessage(xmppMessage); + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + + connection.addPacketListener(listener, filter); + } + + + /** + * Sets a filter for all the incoming XMPP-Messages on the From-JID & To-JID (XMPP-Account IDs) + * passed in. Also creates a listener for the incoming messages and connects the listener to + * the XMPPConnection alongside the set filter. + * + * @param senderJID the From-JID (XMPP-Account ID) to which the filter is to be set. + * @param receiverJID the To-JID (XMPP-Account ID) to which the filter is to be set. + * @param andCondition if true: then filter is set with 'AND' operator (senderJID && + * receiverJID), + * if false: then the filter is set with 'OR' operator (senderJID | + * receiverJID) + */ + protected void setMessageFilterAndListener(String senderJID, String receiverJID, boolean + andCondition) { + PacketFilter jidFilter; + + if (andCondition) { + jidFilter = new AndFilter(new FromContainsFilter(senderJID), new ToContainsFilter( + receiverJID)); + } else { + jidFilter = new OrFilter(new FromContainsFilter(senderJID), new ToContainsFilter( + receiverJID)); + } + + filter = new AndFilter(new PacketTypeFilter(Message.class), jidFilter); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + processIncomingMessage(xmppMessage); + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + + connection.addPacketListener(listener, filter); + } + + + /** + * Sends an XMPP message. Calls the overloaded method with Subject set to "Reply-From-Device" + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param message the XMPP-Message that is to be sent. + */ + protected void sendXMPPMessage(String JID, String message) { + sendXMPPMessage(JID, message, "XMPP-Message"); + } + + + /** + * Overloaded method to send an XMPP message. Includes the subject to be mentioned in the + * message that is sent. + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param message the XMPP-Message that is to be sent. + * @param subject the subject that the XMPP-Message would carry. + */ + protected void sendXMPPMessage(String JID, String message, String subject) { + Message xmppMessage = new Message(); + xmppMessage.setTo(JID); + xmppMessage.setSubject(subject); + xmppMessage.setBody(message); + xmppMessage.setType(Message.Type.chat); + sendXMPPMessage(JID, xmppMessage); + } + + + /** + * Sends an XMPP message. + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param xmppMessage the XMPP-Message that is to be sent. + */ + protected void sendXMPPMessage(String JID, Message xmppMessage) { + connection.sendPacket(xmppMessage); + if (log.isDebugEnabled()) { + log.debug("Message: '" + xmppMessage.getBody() + "' sent to XMPP JID [" + JID + + "] sent successfully."); + } + } + + + /** + * Disables default debugger provided by the XMPPConnection. + */ + protected void disableDebugger() { + connection.DEBUG_ENABLED = false; + } + + + /** + * Closes the connection to the XMPP Server. + */ + public void closeConnection() { + if (connection != null && isConnected()) { + connection.disconnect(); + } + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/VirtualHardwareManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/VirtualHardwareManager.java new file mode 100644 index 000000000..59a13bb87 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/VirtualHardwareManager.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.virtual; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.virtual.ui.AgentUI; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.sampled.Clip; +import javax.swing.*; +import java.io.IOException; +import java.io.InputStream; + +/** + * This class use to emulate virtual hardware functionality + */ +public class VirtualHardwareManager { + + private static final Log log = LogFactory.getLog(VirtualHardwareManager.class); + + private static VirtualHardwareManager virtualHardwareManager; + + private AgentUI agentUI; + private Sequencer sequencer = null; + + private int temperature = 30, humidity = 30; + private int temperatureMin = 20, temperatureMax = 50, humidityMin = 20, humidityMax = 50; + private int temperatureSVF = 50, humiditySVF = 50; + private boolean isTemperatureRandomized, isHumidityRandomized; + private boolean isTemperatureSmoothed, isHumiditySmoothed; + + private VirtualHardwareManager(){ + } + + public static VirtualHardwareManager getInstance(){ + if (virtualHardwareManager == null){ + virtualHardwareManager = new VirtualHardwareManager(); + } + return virtualHardwareManager; + } + + public void init(){ + try { + // Set System L&F for Device UI + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (UnsupportedLookAndFeelException e) { + log.error( + "'UnsupportedLookAndFeelException' error occurred whilst initializing the" + + " Agent UI."); + } catch (ClassNotFoundException e) { + log.error( + "'ClassNotFoundException' error occurred whilst initializing the Agent UI."); + } catch (InstantiationException e) { + log.error( + "'InstantiationException' error occurred whilst initializing the Agent UI."); + } catch (IllegalAccessException e) { + log.error( + "'IllegalAccessException' error occurred whilst initializing the Agent UI."); + } + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + agentUI = new AgentUI(); + agentUI.setVisible(true); + } + }); + setAudioSequencer(); + } + + /** + * Get temperature from emulated device + * @return Temperature + */ + public int getTemperature() { + if (isTemperatureRandomized) { + temperature = getRandom(temperatureMax, temperatureMin, temperature, + isTemperatureSmoothed, temperatureSVF); + agentUI.updateTemperature(temperature); + } + return temperature; + } + + public void setTemperature(int temperature) { + this.temperature = temperature; + } + + /** + * Get humidity from emulated device + * @return Humidity + */ + public int getHumidity() { + if (isHumidityRandomized) { + humidity = getRandom(humidityMax, humidityMin, humidity, isHumiditySmoothed, + humiditySVF); + agentUI.updateHumidity(humidity); + } + return humidity; + } + + public void setHumidity(int humidity) { + this.humidity = humidity; + } + + public void setTemperatureMin(int temperatureMin) { + this.temperatureMin = temperatureMin; + } + + public void setTemperatureMax(int temperatureMax) { + this.temperatureMax = temperatureMax; + } + + public void setHumidityMin(int humidityMin) { + this.humidityMin = humidityMin; + } + + public void setHumidityMax(int humidityMax) { + this.humidityMax = humidityMax; + } + + public void setIsHumidityRandomized(boolean isHumidityRandomized) { + this.isHumidityRandomized = isHumidityRandomized; + } + + public void setIsTemperatureRandomized(boolean isTemperatureRandomized) { + this.isTemperatureRandomized = isTemperatureRandomized; + } + + public void setTemperatureSVF(int temperatureSVF) { + this.temperatureSVF = temperatureSVF; + } + + public void setHumiditySVF(int humiditySVF) { + this.humiditySVF = humiditySVF; + } + + public void setIsTemperatureSmoothed(boolean isTemperatureSmoothed) { + this.isTemperatureSmoothed = isTemperatureSmoothed; + } + + public void setIsHumiditySmoothed(boolean isHumiditySmoothed) { + this.isHumiditySmoothed = isHumiditySmoothed; + } + + public void changeAlarmStatus(boolean isOn) { + agentUI.setAlarmStatus(isOn); + + if (isOn) { + sequencer.start(); + } else { + sequencer.stop(); + } + } + + public void addToPolicyLog(String policy) { + agentUI.addToPolicyLog(policy); + } + + + private int getRandom(int max, int min, int current, boolean isSmoothed, int svf) { + + if (isSmoothed) { + int offset = (max - min) * svf / 100; + double mx = current + offset; + max = (mx > max) ? max : (int) Math.round(mx); + + double mn = current - offset; + min = (mn < min) ? min : (int) Math.round(mn); + } + + double rnd = Math.random() * (max - min) + min; + return (int) Math.round(rnd); + + } + + private void setAudioSequencer() { + InputStream audioSrc = AgentUtilOperations.class.getResourceAsStream( + "/" + AgentConstants.AUDIO_FILE_NAME); + Sequence sequence; + + try { + sequence = MidiSystem.getSequence(audioSrc); + sequencer = MidiSystem.getSequencer(); + sequencer.open(); + sequencer.setSequence(sequence); + } catch (InvalidMidiDataException e) { + log.error("AudioReader: Error whilst setting MIDI Audio reader sequence"); + } catch (IOException e) { + log.error("AudioReader: Error whilst getting audio sequence from stream"); + } catch (MidiUnavailableException e) { + log.error("AudioReader: Error whilst openning MIDI Audio reader sequencer"); + } + + sequencer.setLoopCount(Clip.LOOP_CONTINUOUSLY); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/ui/AgentUI.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/ui/AgentUI.java new file mode 100644 index 000000000..96546e5b6 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/advanced/virtual/ui/AgentUI.java @@ -0,0 +1,1085 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.virtual.ui; + +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.virtual.VirtualHardwareManager; + +import javax.swing.*; +import java.awt.*; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; + +public class AgentUI extends JFrame { + + private boolean isTemperatureRandomized, isHumidityRandomized; + private boolean isTemperatureSmoothed, isHumiditySmoothed; + + private volatile boolean isAlarmOn = false; + + private final Object _lock = new Object(); + + private JLabel picLabelBulbOn, picLabelBulbOff; + + private volatile java.util.List policyLogs = new ArrayList<>(); + + // Variables declaration - do not modify + private JButton btnControl; + private JButton btnView; + private JCheckBox chkbxEmulate; + private JCheckBox chkbxHumidityRandom; + private JCheckBox chkbxHumiditySmooth; + private JCheckBox chkbxTemperatureRandom; + private JCheckBox chkbxTemperatureSmooth; + private JComboBox cmbInterface; + private JComboBox cmbPeriod; + private JComboBox cmbProtocol; + private JLabel jLabel1; + private JLabel jLabel10; + private JLabel jLabel11; + private JLabel jLabel12; + private JLabel jLabel2; + private JLabel jLabel20; + private JLabel jLabel23; + private JLabel jLabel24; + private JLabel jLabel25; + private JLabel jLabel3; + private JLabel jLabel4; + private JLabel jLabel5; + private JLabel jLabel6; + private JLabel jLabel7; + private JLabel jLabel8; + private JLabel jLabel9; + private JPanel jPanel1; + private JPanel jPanel2; + private JPanel jPanel3; + private JPanel jPanel4; + private JPanel jPanel6; + private JPanel jPanel7; + private JPanel jPanel8; + private JPanel jPanel9; + private JScrollPane jScrollPane1; + private JSeparator jSeparator1; + private JSeparator jSeparator5; + private JLabel lblAgentName; + private JLabel lblStatus; + private JPanel pnlBulbStatus; + private JSpinner spinnerHumidity; + private JSpinner spinnerInterval; + private JSpinner spinnerTemperature; + private JTextArea txtAreaLogs; + private JTextField txtHumidityMax; + private JTextField txtHumidityMin; + private JTextField txtHumiditySVF; + private JTextField txtTemperatureMax; + private JTextField txtTemperatureMin; + private JTextField txtTemperatureSVF; + // End of variables declaration + + //Update UI from AgentManager changes + private Runnable uiUpdater = new Runnable() { + @Override + public void run() { + while (true) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + pnlBulbStatus.removeAll(); + pnlBulbStatus.add(isAlarmOn ? picLabelBulbOn : picLabelBulbOff); + pnlBulbStatus.updateUI(); + lblStatus.setText(AgentManager.getInstance().getAgentStatus()); + String policy = getPolicyLog(); + if (policy != null){ + txtAreaLogs.append("\n" + policy); + txtAreaLogs.append("\n--------------------------------------------------\n"); + } + if (isTemperatureRandomized) { + txtTemperatureMinActionPerformed(null); + txtTemperatureMaxActionPerformed(null); + if (isTemperatureSmoothed) { + txtTemperatureSVFActionPerformed(null); + } + } + if (isHumidityRandomized) { + txtHumidityMinActionPerformed(null); + txtHumidityMaxActionPerformed(null); + if (isHumiditySmoothed) { + txtHumiditySVFActionPerformed(null); + } + } + } + }); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + } + } + }; + + + /** + * Creates new form AgentUI + */ + public AgentUI() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + private void initComponents() { + + lblAgentName = new JLabel(); + jLabel2 = new JLabel(); + jPanel1 = new JPanel(); + jLabel3 = new JLabel(); + pnlBulbStatus = new JPanel(); + jPanel2 = new JPanel(); + jLabel4 = new JLabel(); + chkbxTemperatureRandom = new JCheckBox(); + jSeparator1 = new JSeparator(); + jPanel7 = new JPanel(); + jLabel5 = new JLabel(); + txtTemperatureMin = new JTextField(); + jLabel6 = new JLabel(); + txtTemperatureMax = new JTextField(); + jLabel10 = new JLabel(); + txtTemperatureSVF = new JTextField(); + spinnerTemperature = new JSpinner(); + chkbxTemperatureSmooth = new JCheckBox(); + jPanel6 = new JPanel(); + jLabel20 = new JLabel(); + btnView = new JButton(); + btnControl = new JButton(); + lblStatus = new JLabel(); + jPanel8 = new JPanel(); + jLabel23 = new JLabel(); + chkbxHumidityRandom = new JCheckBox(); + jSeparator5 = new JSeparator(); + jPanel9 = new JPanel(); + jLabel24 = new JLabel(); + txtHumidityMin = new JTextField(); + jLabel25 = new JLabel(); + txtHumidityMax = new JTextField(); + txtHumiditySVF = new JTextField(); + jLabel11 = new JLabel(); + spinnerHumidity = new JSpinner(); + chkbxHumiditySmooth = new JCheckBox(); + jPanel3 = new JPanel(); + jLabel7 = new JLabel(); + spinnerInterval = new JSpinner(); + jLabel8 = new JLabel(); + jLabel9 = new JLabel(); + cmbProtocol = new JComboBox(); + jLabel12 = new JLabel(); + cmbInterface = new JComboBox(); + jScrollPane1 = new JScrollPane(); + txtAreaLogs = new JTextArea(); + jPanel4 = new JPanel(); + chkbxEmulate = new JCheckBox(); + cmbPeriod = new JComboBox(); + jLabel1 = new JLabel(); + + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + setTitle("Fire Alarm Emulator"); + setResizable(false); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation(dim.width / 2 - 650 / 2, dim.height / 2 - 440 / 2); + + lblAgentName.setFont(new Font("Cantarell", 1, 24)); // NOI18N + lblAgentName.setHorizontalAlignment(SwingConstants.LEFT); + lblAgentName.setText("Device Name: " + AgentManager.getInstance().getDeviceName()); + + jLabel2.setHorizontalAlignment(SwingConstants.CENTER); + jLabel2.setText("Copyright (c) 2015, WSO2 Inc."); + + jPanel1.setBackground(new Color(220, 220, 220)); + + jLabel3.setFont(new Font("Cantarell", 0, 18)); // NOI18N + jLabel3.setHorizontalAlignment(SwingConstants.CENTER); + jLabel3.setText("Alarm Status"); + + pnlBulbStatus.setBackground(new Color(220, 220, 220)); + + GroupLayout pnlBulbStatusLayout = new GroupLayout(pnlBulbStatus); + pnlBulbStatus.setLayout(pnlBulbStatusLayout); + pnlBulbStatusLayout.setHorizontalGroup( + pnlBulbStatusLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) + ); + pnlBulbStatusLayout.setVerticalGroup( + pnlBulbStatusLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGap(0, 167, Short.MAX_VALUE) + ); + + GroupLayout jPanel1Layout = new GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup( + GroupLayout.Alignment.TRAILING) + .addComponent(pnlBulbStatus, + GroupLayout + .DEFAULT_SIZE, + GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addComponent(jLabel3, + GroupLayout.DEFAULT_SIZE, + 190, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel3) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlBulbStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + + jPanel2.setBackground(new Color(220, 220, 220)); + + jLabel4.setFont(new Font("Cantarell", 0, 18)); // NOI18N + jLabel4.setHorizontalAlignment(SwingConstants.CENTER); + jLabel4.setText("Temperature"); + + chkbxTemperatureRandom.setText("Randomize Data"); + chkbxTemperatureRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureRandomActionPerformed(evt); + } + }); + + jSeparator1.setOrientation(SwingConstants.VERTICAL); + + jPanel7.setBackground(new Color(220, 220, 220)); + + jLabel5.setHorizontalAlignment(SwingConstants.LEFT); + jLabel5.setText("Min"); + + txtTemperatureMin.setHorizontalAlignment(JTextField.CENTER); + txtTemperatureMin.setText("20"); + txtTemperatureMin.setEnabled(false); + txtTemperatureMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMinActionPerformed(evt); + } + }); + + jLabel6.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel6.setText("Max"); + + txtTemperatureMax.setHorizontalAlignment(JTextField.CENTER); + txtTemperatureMax.setText("50"); + txtTemperatureMax.setEnabled(false); + txtTemperatureMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMaxActionPerformed(evt); + } + }); + + jLabel10.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel10.setText("SV %"); + + txtTemperatureSVF.setHorizontalAlignment(JTextField.CENTER); + txtTemperatureSVF.setText("50"); + txtTemperatureSVF.setEnabled(false); + txtTemperatureSVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureSVFActionPerformed(evt); + } + }); + + GroupLayout jPanel7Layout = new GroupLayout(jPanel7); + jPanel7.setLayout(jPanel7Layout); + jPanel7Layout.setHorizontalGroup( + jPanel7Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel7Layout.createSequentialGroup() + .addComponent(jLabel5) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMin, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel6) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMax, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel10) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureSVF, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addContainerGap(GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE)) + ); + jPanel7Layout.setVerticalGroup( + jPanel7Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel7Layout + .createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addGroup(jPanel7Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(txtTemperatureMin, + GroupLayout + .PREFERRED_SIZE, + GroupLayout + .DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(txtTemperatureMax, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6) + .addComponent(jLabel5) + .addComponent(jLabel10) + .addComponent(txtTemperatureSVF, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE)) + .addGap(35, 35, 35)) + ); + + spinnerTemperature.setFont(new Font("Cantarell", 1, 24)); // NOI18N + spinnerTemperature.setModel(new SpinnerNumberModel(30, 0, 100, 1)); + spinnerTemperature.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerTemperatureStateChanged(evt); + } + }); + + chkbxTemperatureSmooth.setText("Smooth Variation"); + chkbxTemperatureSmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureSmoothActionPerformed(evt); + } + }); + + GroupLayout jPanel2Layout = new GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spinnerTemperature)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 6, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jPanel7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(chkbxTemperatureRandom) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxTemperatureSmooth))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jSeparator1) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent( + chkbxTemperatureRandom) + .addComponent( + chkbxTemperatureSmooth)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel7, GroupLayout.PREFERRED_SIZE, 51, GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel4, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerTemperature))) + .addContainerGap()) + ); + + jPanel6.setBackground(new Color(253, 254, 209)); + + jLabel20.setText("Connection Status:"); + jLabel20.setVerticalTextPosition(SwingConstants.TOP); + + btnView.setText("View Device Data"); + btnView.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnViewMouseClicked(evt); + } + }); + + btnControl.setText("Control Device"); + btnControl.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnControlMouseClicked(evt); + } + }); + + lblStatus.setFont(new Font("Cantarell", 1, 15)); // NOI18N + lblStatus.setText("Not Connected"); + + GroupLayout jPanel6Layout = new GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel6Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel20) + .addPreferredGap(LayoutStyle + .ComponentPlacement.RELATED) + .addComponent(lblStatus, GroupLayout + .DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnControl) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnView) + .addContainerGap()) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup( + GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel20, + GroupLayout.DEFAULT_SIZE, + GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(btnView, + GroupLayout.DEFAULT_SIZE, + GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addComponent(btnControl) + .addComponent(lblStatus))) + .addContainerGap()) + ); + + jPanel8.setBackground(new Color(220, 220, 220)); + + jLabel23.setFont(new Font("Cantarell", 0, 18)); // NOI18N + jLabel23.setHorizontalAlignment(SwingConstants.CENTER); + jLabel23.setText("Humidity"); + + chkbxHumidityRandom.setText("Randomize Data"); + chkbxHumidityRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumidityRandomActionPerformed(evt); + } + }); + + jSeparator5.setOrientation(SwingConstants.VERTICAL); + + jPanel9.setBackground(new Color(220, 220, 220)); + + jLabel24.setHorizontalAlignment(SwingConstants.LEFT); + jLabel24.setText("Min"); + + txtHumidityMin.setHorizontalAlignment(JTextField.CENTER); + txtHumidityMin.setText("20"); + txtHumidityMin.setEnabled(false); + txtHumidityMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMinActionPerformed(evt); + } + }); + + jLabel25.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel25.setText("Max"); + + txtHumidityMax.setHorizontalAlignment(JTextField.CENTER); + txtHumidityMax.setText("50"); + txtHumidityMax.setEnabled(false); + txtHumidityMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMaxActionPerformed(evt); + } + }); + + txtHumiditySVF.setHorizontalAlignment(JTextField.CENTER); + txtHumiditySVF.setText("50"); + txtHumiditySVF.setEnabled(false); + txtHumiditySVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumiditySVFActionPerformed(evt); + } + }); + + jLabel11.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel11.setText("SV %"); + + GroupLayout jPanel9Layout = new GroupLayout(jPanel9); + jPanel9.setLayout(jPanel9Layout); + jPanel9Layout.setHorizontalGroup( + jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createSequentialGroup() + .addComponent(jLabel24) + .addPreferredGap(LayoutStyle + .ComponentPlacement.RELATED) + .addComponent(txtHumidityMin, GroupLayout + .PREFERRED_SIZE, 45, GroupLayout + .PREFERRED_SIZE) + .addPreferredGap(LayoutStyle + .ComponentPlacement.RELATED) + .addComponent(jLabel25) + .addPreferredGap(LayoutStyle + .ComponentPlacement.RELATED) + .addComponent(txtHumidityMax, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel11) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumiditySVF, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel9Layout.setVerticalGroup( + jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel9Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addGroup(jPanel9Layout.createParallelGroup( + GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(jLabel11) + .addComponent(txtHumiditySVF, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel9Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(txtHumidityMin, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(txtHumidityMax, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel25) + .addComponent(jLabel24))) + .addGap(35, 35, 35)) + ); + + spinnerHumidity.setFont(new Font("Cantarell", 1, 24)); // NOI18N + spinnerHumidity.setModel(new SpinnerNumberModel(30, 0, 100, 1)); + spinnerHumidity.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerHumidityStateChanged(evt); + } + }); + + chkbxHumiditySmooth.setText("Smooth Variation"); + chkbxHumiditySmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumiditySmoothActionPerformed(evt); + } + }); + + GroupLayout jPanel8Layout = new GroupLayout(jPanel8); + jPanel8.setLayout(jPanel8Layout); + jPanel8Layout.setHorizontalGroup( + jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jLabel23, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerHumidity)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator5, GroupLayout.PREFERRED_SIZE, 6, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(jPanel9, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(chkbxHumidityRandom) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxHumiditySmooth))) + .addContainerGap()) + ); + jPanel8Layout.setVerticalGroup( + jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jSeparator5) + .addGroup(jPanel8Layout.createSequentialGroup() + .addGroup(jPanel8Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent( + chkbxHumidityRandom) + .addComponent( + chkbxHumiditySmooth)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel9, GroupLayout.PREFERRED_SIZE, 51, GroupLayout.PREFERRED_SIZE) + .addGap(0, 1, Short.MAX_VALUE)) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(jLabel23, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE) + .addPreferredGap + (LayoutStyle.ComponentPlacement.RELATED) + .addComponent + (spinnerHumidity))) + .addContainerGap()) + ); + + jPanel3.setBackground(new Color(207, 233, 234)); + + jLabel7.setText("Data Push Interval:"); + + spinnerInterval.setModel(new SpinnerNumberModel(Integer.valueOf(5), Integer + .valueOf(1), null, Integer.valueOf(1))); + spinnerInterval.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerIntervalStateChanged(evt); + } + }); + + jLabel8.setText("Seconds"); + + jLabel9.setText("Protocol:"); + + cmbProtocol.setModel(new DefaultComboBoxModel(new String[] { "MQTT", "XMPP", + "HTTP" })); + cmbProtocol.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbProtocolActionPerformed(evt); + } + }); + + jLabel12.setText("Interface:"); + + cmbInterface.setModel(new DefaultComboBoxModel(new String[] { "eth0" })); + cmbInterface.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbInterfaceActionPerformed(evt); + } + }); + + GroupLayout jPanel3Layout = new GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel7) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerInterval, GroupLayout.PREFERRED_SIZE, 55, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel8) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel12) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbInterface, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel9) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbProtocol, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel3Layout + .createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addGroup(jPanel3Layout.createParallelGroup( + GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(jLabel12) + .addComponent(cmbInterface, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(jLabel7) + .addComponent(spinnerInterval, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel8) + .addComponent(jLabel9) + .addComponent(cmbProtocol, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + txtAreaLogs.setBackground(new Color(1, 1, 1)); + txtAreaLogs.setColumns(20); + txtAreaLogs.setFont(new Font("Courier 10 Pitch", Font.BOLD, 9)); // NOI18N + txtAreaLogs.setForeground(new Color(0, 255, 0)); + txtAreaLogs.setRows(5); + jScrollPane1.setViewportView(txtAreaLogs); + + jPanel4.setBackground(new Color(169, 253, 173)); + + chkbxEmulate.setText("Emulate data"); + chkbxEmulate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxEmulateActionPerformed(evt); + } + }); + + cmbPeriod.setModel(new DefaultComboBoxModel(new String[] { "1 hour", "1 day", "1 week", "1 month " })); + cmbPeriod.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbPeriodActionPerformed(evt); + } + }); + + jLabel1.setText("Emulation Period"); + + GroupLayout jPanel4Layout = new GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addComponent(chkbxEmulate) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbPeriod, GroupLayout.PREFERRED_SIZE, 162, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addGroup(jPanel4Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(chkbxEmulate) + .addComponent(cmbPeriod, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1)) + .addContainerGap()) + ); + + GroupLayout layout = new GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addComponent(lblAgentName, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel6, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup( + GroupLayout.Alignment.LEADING) + .addComponent( + jPanel8, + GroupLayout.DEFAULT_SIZE, + GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addComponent( + jPanel2, + GroupLayout.DEFAULT_SIZE, + GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE))) + .addComponent(jLabel2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAgentName, GroupLayout.PREFERRED_SIZE, 53, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel8, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 115, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2, GroupLayout.PREFERRED_SIZE, 28, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + + chkbxTemperatureSmooth.setEnabled(false); + chkbxTemperatureSmooth.setEnabled(false); + + cmbInterface.removeAllItems(); + for (String item : AgentManager.getInstance().getInterfaceList()){ + cmbInterface.addItem(item); + } + cmbInterface.setEnabled(false); + + cmbProtocol.removeAllItems(); + for (String item : AgentManager.getInstance().getProtocolList()){ + cmbProtocol.addItem(item); + } + cmbProtocol.setSelectedItem(AgentConstants.DEFAULT_PROTOCOL); + + URL urlAlarmOn = this.getClass().getResource("/alarm-on.gif"); + ImageIcon imageIconAlarmOn = new ImageIcon(urlAlarmOn); + + URL urlAlarmOff = this.getClass().getResource("/alarm-off.gif"); + ImageIcon imageIconAlarmOff = new ImageIcon(urlAlarmOff); + + picLabelBulbOn = new JLabel(imageIconAlarmOn); + picLabelBulbOn.setSize(pnlBulbStatus.getSize()); + + picLabelBulbOff = new JLabel(imageIconAlarmOff); + picLabelBulbOff.setSize(pnlBulbStatus.getSize()); + + addToPolicyLog(AgentUtilOperations.formatMessage(AgentManager.getInstance().getInitialPolicy())); + new Thread(uiUpdater).start(); + + AgentManager.getInstance().setDeviceReady(true); + } + + private void btnControlMouseClicked(java.awt.event.MouseEvent evt) { + Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + try { + URI uri = new URI(AgentManager.getInstance().getDeviceMgtControlUrl()); + desktop.browse(uri); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void btnViewMouseClicked(java.awt.event.MouseEvent evt) { + Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + try { + URI uri = new URI(AgentManager.getInstance().getDeviceMgtAnalyticUrl()); + desktop.browse(uri); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void chkbxTemperatureRandomActionPerformed(java.awt.event.ActionEvent evt) { + isTemperatureRandomized = chkbxTemperatureRandom.isSelected(); + VirtualHardwareManager.getInstance().setIsTemperatureRandomized(isTemperatureRandomized); + spinnerTemperature.setEnabled(!isTemperatureRandomized); + txtTemperatureMax.setEnabled(isTemperatureRandomized); + txtTemperatureMin.setEnabled(isTemperatureRandomized); + chkbxTemperatureSmooth.setEnabled(isTemperatureRandomized); + txtTemperatureSVF.setEnabled(isTemperatureRandomized && isTemperatureSmoothed); + } + + private void chkbxHumidityRandomActionPerformed(java.awt.event.ActionEvent evt) { + isHumidityRandomized = chkbxHumidityRandom.isSelected(); + VirtualHardwareManager.getInstance().setIsHumidityRandomized(isHumidityRandomized); + spinnerHumidity.setEnabled(!isHumidityRandomized); + txtHumidityMax.setEnabled(isHumidityRandomized); + txtHumidityMin.setEnabled(isHumidityRandomized); + chkbxHumiditySmooth.setEnabled(isHumidityRandomized); + txtTemperatureSVF.setEnabled(isHumidityRandomized && isHumiditySmoothed); + } + + private void spinnerTemperatureStateChanged(javax.swing.event.ChangeEvent evt) { + if (!isTemperatureRandomized) { + try { + int temperature = Integer.parseInt(spinnerTemperature.getValue().toString()); + VirtualHardwareManager.getInstance().setTemperature(temperature); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE); + spinnerTemperature.setValue(VirtualHardwareManager.getInstance().getTemperature()); + } + } + } + + private void spinnerHumidityStateChanged(javax.swing.event.ChangeEvent evt) { + if (!isHumidityRandomized) { + try { + int humidity = Integer.parseInt(spinnerHumidity.getValue().toString()); + VirtualHardwareManager.getInstance().setHumidity(humidity); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE); + spinnerHumidity.setValue(VirtualHardwareManager.getInstance().getHumidity()); + } + } + } + + private void txtTemperatureMinActionPerformed(java.awt.event.ActionEvent evt) { + try { + int temperature = Integer.parseInt(txtTemperatureMin.getText()); + VirtualHardwareManager.getInstance().setTemperatureMin(temperature); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE); + txtTemperatureMin.setText("20"); + } + } + + private void txtTemperatureMaxActionPerformed(java.awt.event.ActionEvent evt) { + try { + int temperature = Integer.parseInt(txtTemperatureMax.getText()); + VirtualHardwareManager.getInstance().setTemperatureMax(temperature); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE); + txtTemperatureMax.setText("50"); + } + } + + private void txtHumidityMinActionPerformed(java.awt.event.ActionEvent evt) { + try { + int humidity = Integer.parseInt(txtHumidityMin.getText()); + VirtualHardwareManager.getInstance().setHumidityMin(humidity); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE); + txtHumidityMin.setText("20"); + } + } + + private void txtHumidityMaxActionPerformed(java.awt.event.ActionEvent evt) { + try { + int humidity = Integer.parseInt(txtHumidityMax.getText()); + VirtualHardwareManager.getInstance().setHumidityMax(humidity); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE); + txtHumidityMax.setText("50"); + } + } + + private void spinnerIntervalStateChanged(javax.swing.event.ChangeEvent evt) { + try { + int interval = Integer.parseInt(spinnerInterval.getValue().toString()); + AgentManager.getInstance().setPushInterval(interval); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid time interval value", "Error", JOptionPane.ERROR_MESSAGE); + spinnerInterval.setValue(5); + } + } + + private void cmbInterfaceActionPerformed(java.awt.event.ActionEvent evt) { + AgentManager.getInstance().setInterface(cmbInterface.getSelectedIndex()); + } + + private void cmbProtocolActionPerformed(java.awt.event.ActionEvent evt) { + if (cmbProtocol.getSelectedIndex() != -1 && cmbProtocol.getItemAt( + cmbProtocol.getSelectedIndex()).equals(AgentConstants.HTTP_PROTOCOL)) { + cmbInterface.setEnabled(true); + } else { + cmbInterface.setEnabled(false); + } + + AgentManager.getInstance().setProtocol(cmbProtocol.getSelectedIndex()); + + } + + private void txtTemperatureSVFActionPerformed(java.awt.event.ActionEvent evt) { + try { + int temperatureSVF = Integer.parseInt(txtTemperatureSVF.getText()); + VirtualHardwareManager.getInstance().setTemperatureSVF(temperatureSVF); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid value", "Error", JOptionPane.ERROR_MESSAGE); + txtTemperatureSVF.setText("50"); + } + } + + private void txtHumiditySVFActionPerformed(java.awt.event.ActionEvent evt) { + try { + int humiditySVF = Integer.parseInt(txtHumiditySVF.getText()); + VirtualHardwareManager.getInstance().setHumiditySVF(humiditySVF); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid value", "Error", JOptionPane.ERROR_MESSAGE); + txtHumiditySVF.setText("50"); + } + } + + private void chkbxTemperatureSmoothActionPerformed(java.awt.event.ActionEvent evt) { + isTemperatureSmoothed = chkbxTemperatureSmooth.isSelected(); + txtTemperatureSVF.setEnabled(isTemperatureSmoothed); + VirtualHardwareManager.getInstance().setIsTemperatureSmoothed(isTemperatureSmoothed); + } + + private void chkbxHumiditySmoothActionPerformed(java.awt.event.ActionEvent evt) { + isHumiditySmoothed = chkbxHumiditySmooth.isSelected(); + txtHumiditySVF.setEnabled(isHumiditySmoothed); + VirtualHardwareManager.getInstance().setIsHumiditySmoothed(isHumiditySmoothed); + } + + private void cmbPeriodActionPerformed(java.awt.event.ActionEvent evt) { + // TODO add your handling code here: + } + + private void chkbxEmulateActionPerformed(java.awt.event.ActionEvent evt) { + // TODO add your handling code here: + } + + public void setAlarmStatus(boolean isAlarmOn) { + this.isAlarmOn = isAlarmOn; + } + + public void updateTemperature(int temperature) { + spinnerTemperature.setValue(temperature); + spinnerTemperature.updateUI(); + } + + public void updateHumidity(int humidity) { + spinnerHumidity.setValue(humidity); + spinnerHumidity.updateUI(); + } + + public void addToPolicyLog(String policy) { + synchronized (this._lock) { + policyLogs.add(policy); + } + } + + private String getPolicyLog() { + synchronized (this._lock) { + if (policyLogs.size() > 0) { + String policy = policyLogs.get(0); + policyLogs.remove(0); + return policy; + } else { + return null; + } + } + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/alarm-off.gif b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/alarm-off.gif new file mode 100644 index 0000000000000000000000000000000000000000..c346605ad00627e4bda392cd37ab24bde7643395 GIT binary patch literal 4265 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 C_s;DA literal 0 HcmV?d00001 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/cep_query.txt b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/cep_query.txt new file mode 100644 index 000000000..17546ece2 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/cep_query.txt @@ -0,0 +1,11 @@ +define stream fireAlarmEventStream (deviceID string, temp int); +from fireAlarmEventStream#window.time(7886776 sec) +select deviceID, max(temp) as maxValue +group by deviceID +insert into analyzeStream for expired-events; +from analyzeStream[maxValue < 88] +select maxValue +insert into bulbOnStream; +from fireAlarmEventStream[temp > 1093] +select deviceID, temp +insert into bulbOffStream; \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/deviceConfig.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/deviceConfig.properties new file mode 100644 index 000000000..930742a2a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/deviceConfig.properties @@ -0,0 +1,33 @@ +# +# Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +# +# Licensed 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. +# +# + +#[Device-Configurations] +server-name=WSO2IoTServer +owner=shabirmean +deviceId=t4ctwq8qfl11 +device-name=SMEAN_t4ctwq8qfl11 +controller-context=/virtual_firealarm/controller +https-ep=https://localhost:9443 +http-ep=http://localhost:9763 +apim-ep=http://192.168.67.21:8281 +mqtt-ep=tcp://192.168.67.21:1883 +xmpp-ep=http://204.232.188.215:5222 +auth-method=token +auth-token=79d68b50ae5f5a06e812889979b3453 +refresh-token=8bdda6359dddad218cff3354d5a8cb3b +network-interface=en0 +push-interval=14 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/fireAlarmSound.mid b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/resources/fireAlarmSound.mid new file mode 100644 index 0000000000000000000000000000000000000000..d1a2241b2d87d668b9cfa999f05be6a8c477d895 GIT binary patch literal 6719 zcmeI%&rc&|7zglY+L=<>4Yh|&?8cA@YYBz~Q>>7XY15%lD8d3Q;20ul)6PO!VUezl zB_jA>{7SQ2H^mm&olGP zJ2TJw%nQsdZ6t}vMjSb~-{+QgFS9L)3btqF;=7mCUGc&NDl7>iQ=)>x^OooARCwK@ zZyniZ(aJrzM}?QDl;au|toEq-*4yfKLZt$Kc4|(XP&287Dtca_g2?sIL#L*l;W)d+ zZng7vo84jmhaR3M@uFtoI5r@T74j&7tuA3Ml+h^A(|nnUn9RJ^%MC?8rCSRNy9|p zqwdy-9l}CxB6d_wl!bhVvXHM)v{UEGKYv0mOzOaOv1ji`S+G)I72q!yM?-gK$&)2t zmcm)RCfpglEIb+g@%u8YJ}8`lr{QUM8lHylz<1y~@E!OTd<(t>--2(#H{qM`P53%| z9lj1TiJ4 zj(9>kV%4&Dy!ooa<(m1j>>~!u@{XW|v0Y0q%^(uMW@~Y*AfaKy!a%p(<8= zd21G`#eBKg#|dqJWIv&dl|INX{!Gp~EJrK5)l2?--C-@~s?XkXs_T1CZdgz0B~~6h zO_`L?%X$e}Tn9!8eYYqauoC){0(8)@jx2vXvW|*LbFoiS8eP@)-n*(Sq?CSROI}FH z=YAol0rla^&c}=8Z6-5oD$g7KkjA<1 zdEr*qLgV&p)f;(FRr3|a+V)$_NrxooVxJ~7+R*lL357P4jIkxthOGWdP6O)0m7R|l z%deOuZPPi;#`?rgd5PW7XN%Xie~vw-2nC}w5uwQ_g(5T+rRj^ggnnb$GYng3rkAFB zX|k8bZ6tsFPUmmRiG2{Ir>z&bMB@?#C7O_EQlgMVQxZ)}6qablORshppNDWr(+-++ z(72W4$DEh=OCayMU7nZ14+8%e`MKN8mPL>8IxFVP#Xe(mGNtY1*_=!%8DmSPl&n4= zrvdfh%Ff4&RvUB~RX0hU}ZIZNn zolU}Kd0UOO>6BH|#_TtVQT=shbKNnf&5vo}PO~Y)-GAh(te7ts`+QN`dw)^M6o1O< zZ{)0@Qpnh)c00dPb3h9@YIC-b;>O5-AI4L1DODvg(tL&EVKI?&xbBup!Y2Imu5g!? ygz*a{MNtMz>YM7$#+7aMZ + + + + + + + + + + Builds, tests, and runs the project VirtualAgentUI. + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/manifest.mf b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/manifest.mf new file mode 100644 index 000000000..328e8e5bc --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/build-impl.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/build-impl.xml new file mode 100644 index 000000000..112454207 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/genfiles.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/genfiles.properties new file mode 100644 index 000000000..a6df38fd8 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=e60df945 +build.xml.script.CRC32=7c331eea +build.xml.stylesheet.CRC32=8064a381@1.75.2.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=e60df945 +nbproject/build-impl.xml.script.CRC32=4fa004f7 +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.properties new file mode 100644 index 000000000..e59ac1df6 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.properties @@ -0,0 +1,2 @@ +compile.on.save=true +user.properties.file=/home/charitha/.netbeans/8.0.2/build.properties diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.xml new file mode 100644 index 000000000..97b7e92bd --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/private/private.xml @@ -0,0 +1,9 @@ + + + + + + file:/home/charitha/NetBeansProjects/VirtualAgentUI/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.properties new file mode 100644 index 000000000..fb798f614 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.properties @@ -0,0 +1,73 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processor.options= +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/VirtualAgentUI.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.8 +javac.target=1.8 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=org.wso2.carbon.device.mgt.iot.agent.virtual.VirtualAgentUI +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.xml new file mode 100644 index 000000000..438f1e6a3 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + VirtualAgentUI + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/bulb-on.jpg b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/bulb-on.jpg new file mode 100644 index 0000000000000000000000000000000000000000..51d40cd834db53f1bf305997832ad4c5f7a00356 GIT binary patch literal 6942 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java new file mode 100644 index 000000000..a2aa2116a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.wso2.carbon.device.mgt.iot.agent.virtual; + +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.wso2.carbon.device.mgt.iot.agent.virtual.ui.AgentUI; + +/** + * + * @author charitha + */ +public class VirtualAgentUI { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + try { + // Set System L&F + UIManager.setLookAndFeel( + UIManager.getSystemLookAndFeelClassName()); + } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { + // handle exception + } + + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + new AgentUI().setVisible(true); + } + }); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form new file mode 100644 index 000000000..0778bef15 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form @@ -0,0 +1,830 @@ + + +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java new file mode 100644 index 000000000..27a177492 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java @@ -0,0 +1,758 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.wso2.carbon.device.mgt.iot.agent.virtual.ui; + +/** + * + * @author charitha + */ +public class AgentUI extends javax.swing.JFrame { + + /** + * Creates new form AgentUI + */ + public AgentUI() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + lblAgentName = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jPanel1 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + pnlBulbStatus = new javax.swing.JPanel(); + jPanel2 = new javax.swing.JPanel(); + jLabel4 = new javax.swing.JLabel(); + chkbxTemperatureRandom = new javax.swing.JCheckBox(); + jSeparator1 = new javax.swing.JSeparator(); + jPanel7 = new javax.swing.JPanel(); + jLabel5 = new javax.swing.JLabel(); + txtTemperatureMin = new javax.swing.JTextField(); + jLabel6 = new javax.swing.JLabel(); + txtTemperatureMax = new javax.swing.JTextField(); + jLabel10 = new javax.swing.JLabel(); + txtTemperatureSVF = new javax.swing.JTextField(); + spinnerTemperature = new javax.swing.JSpinner(); + chkbxTemperatureSmooth = new javax.swing.JCheckBox(); + jPanel6 = new javax.swing.JPanel(); + jLabel20 = new javax.swing.JLabel(); + btnView = new javax.swing.JButton(); + btnControl = new javax.swing.JButton(); + lblStatus = new javax.swing.JLabel(); + jPanel8 = new javax.swing.JPanel(); + jLabel23 = new javax.swing.JLabel(); + chkbxHumidityRandom = new javax.swing.JCheckBox(); + jSeparator5 = new javax.swing.JSeparator(); + jPanel9 = new javax.swing.JPanel(); + jLabel24 = new javax.swing.JLabel(); + txtHumidityMin = new javax.swing.JTextField(); + jLabel25 = new javax.swing.JLabel(); + txtHumidityMax = new javax.swing.JTextField(); + txtHumiditySVF = new javax.swing.JTextField(); + jLabel11 = new javax.swing.JLabel(); + spinnerHumidity = new javax.swing.JSpinner(); + chkbxHumiditySmooth = new javax.swing.JCheckBox(); + jPanel3 = new javax.swing.JPanel(); + jLabel7 = new javax.swing.JLabel(); + spinnerInterval = new javax.swing.JSpinner(); + jLabel8 = new javax.swing.JLabel(); + jLabel9 = new javax.swing.JLabel(); + cmbProtocol = new javax.swing.JComboBox(); + jLabel12 = new javax.swing.JLabel(); + cmbInterface = new javax.swing.JComboBox(); + jScrollPane1 = new javax.swing.JScrollPane(); + txtAreaLogs = new javax.swing.JTextArea(); + jPanel4 = new javax.swing.JPanel(); + chkbxEmulate = new javax.swing.JCheckBox(); + cmbPeriod = new javax.swing.JComboBox(); + jLabel1 = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setTitle("Fire Alarm Emulator"); + setResizable(false); + + lblAgentName.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N + lblAgentName.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + lblAgentName.setText("Device Name: WSO2 IoT Virtual Agent"); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel2.setText("Copyright (c) 2015, WSO2 Inc."); + + jPanel1.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel3.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel3.setText("Bulb Status"); + + pnlBulbStatus.setBackground(new java.awt.Color(220, 220, 220)); + + javax.swing.GroupLayout pnlBulbStatusLayout = new javax.swing.GroupLayout(pnlBulbStatus); + pnlBulbStatus.setLayout(pnlBulbStatusLayout); + pnlBulbStatusLayout.setHorizontalGroup( + pnlBulbStatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) + ); + pnlBulbStatusLayout.setVerticalGroup( + pnlBulbStatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 167, Short.MAX_VALUE) + ); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(pnlBulbStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel3) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlBulbStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + + jPanel2.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel4.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel4.setText("Temperature"); + + chkbxTemperatureRandom.setText("Randomize Data"); + chkbxTemperatureRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureRandomActionPerformed(evt); + } + }); + + jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + + jPanel7.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabel5.setText("Min"); + + txtTemperatureMin.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtTemperatureMin.setText("20"); + txtTemperatureMin.setEnabled(false); + txtTemperatureMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMinActionPerformed(evt); + } + }); + + jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel6.setText("Max"); + + txtTemperatureMax.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtTemperatureMax.setText("50"); + txtTemperatureMax.setEnabled(false); + txtTemperatureMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMaxActionPerformed(evt); + } + }); + + jLabel10.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel10.setText("SV %"); + + txtTemperatureSVF.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtTemperatureSVF.setText("50"); + txtTemperatureSVF.setEnabled(false); + txtTemperatureSVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureSVFActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel7Layout = new javax.swing.GroupLayout(jPanel7); + jPanel7.setLayout(jPanel7Layout); + jPanel7Layout.setHorizontalGroup( + jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel7Layout.createSequentialGroup() + .addComponent(jLabel5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMin, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMax, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel10) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureSVF, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel7Layout.setVerticalGroup( + jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtTemperatureMin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtTemperatureMax, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6) + .addComponent(jLabel5) + .addComponent(jLabel10) + .addComponent(txtTemperatureSVF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(35, 35, 35)) + ); + + spinnerTemperature.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N + spinnerTemperature.setModel(new javax.swing.SpinnerNumberModel(30, 0, 100, 1)); + spinnerTemperature.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerTemperatureStateChanged(evt); + } + }); + + chkbxTemperatureSmooth.setText("Smooth Variation"); + chkbxTemperatureSmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureSmoothActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spinnerTemperature)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(chkbxTemperatureRandom) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxTemperatureSmooth))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSeparator1) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkbxTemperatureRandom) + .addComponent(chkbxTemperatureSmooth)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerTemperature))) + .addContainerGap()) + ); + + jPanel6.setBackground(new java.awt.Color(253, 254, 209)); + + jLabel20.setText("Connection Status:"); + jLabel20.setVerticalTextPosition(javax.swing.SwingConstants.TOP); + + btnView.setText("View Device Data"); + btnView.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnViewMouseClicked(evt); + } + }); + + btnControl.setText("Control Device"); + btnControl.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnControlMouseClicked(evt); + } + }); + + lblStatus.setFont(new java.awt.Font("Cantarell", 1, 15)); // NOI18N + lblStatus.setText("Not Connected"); + + javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel6Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel20) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnControl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnView) + .addContainerGap()) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel20, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnControl) + .addComponent(lblStatus))) + .addContainerGap()) + ); + + jPanel8.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel23.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N + jLabel23.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel23.setText("Humidity"); + + chkbxHumidityRandom.setText("Randomize Data"); + chkbxHumidityRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumidityRandomActionPerformed(evt); + } + }); + + jSeparator5.setOrientation(javax.swing.SwingConstants.VERTICAL); + + jPanel9.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel24.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabel24.setText("Min"); + + txtHumidityMin.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtHumidityMin.setText("20"); + txtHumidityMin.setEnabled(false); + txtHumidityMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMinActionPerformed(evt); + } + }); + + jLabel25.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel25.setText("Max"); + + txtHumidityMax.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtHumidityMax.setText("50"); + txtHumidityMax.setEnabled(false); + txtHumidityMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMaxActionPerformed(evt); + } + }); + + txtHumiditySVF.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtHumiditySVF.setText("50"); + txtHumiditySVF.setEnabled(false); + txtHumiditySVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumiditySVFActionPerformed(evt); + } + }); + + jLabel11.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel11.setText("SV %"); + + javax.swing.GroupLayout jPanel9Layout = new javax.swing.GroupLayout(jPanel9); + jPanel9.setLayout(jPanel9Layout); + jPanel9Layout.setHorizontalGroup( + jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createSequentialGroup() + .addComponent(jLabel24) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumidityMin, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel25) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumidityMax, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel11) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumiditySVF, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel9Layout.setVerticalGroup( + jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel9Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel11) + .addComponent(txtHumiditySVF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtHumidityMin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtHumidityMax, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel25) + .addComponent(jLabel24))) + .addGap(35, 35, 35)) + ); + + spinnerHumidity.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N + spinnerHumidity.setModel(new javax.swing.SpinnerNumberModel(30, 0, 100, 1)); + spinnerHumidity.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerHumidityStateChanged(evt); + } + }); + + chkbxHumiditySmooth.setText("Smooth Variation"); + chkbxHumiditySmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumiditySmoothActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel8Layout = new javax.swing.GroupLayout(jPanel8); + jPanel8.setLayout(jPanel8Layout); + jPanel8Layout.setHorizontalGroup( + jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerHumidity)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(chkbxHumidityRandom) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxHumiditySmooth))) + .addContainerGap()) + ); + jPanel8Layout.setVerticalGroup( + jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSeparator5) + .addGroup(jPanel8Layout.createSequentialGroup() + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkbxHumidityRandom) + .addComponent(chkbxHumiditySmooth)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 1, Short.MAX_VALUE)) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerHumidity))) + .addContainerGap()) + ); + + jPanel3.setBackground(new java.awt.Color(207, 233, 234)); + + jLabel7.setText("Data Push Interval:"); + + spinnerInterval.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(5), Integer.valueOf(1), null, Integer.valueOf(1))); + spinnerInterval.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerIntervalStateChanged(evt); + } + }); + + jLabel8.setText("Seconds"); + + jLabel9.setText("Protocol:"); + + cmbProtocol.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "MQTT", "XMPP", "HTTP" })); + cmbProtocol.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbProtocolActionPerformed(evt); + } + }); + + jLabel12.setText("Interface:"); + + cmbInterface.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "eth0" })); + cmbInterface.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbInterfaceActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel7) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerInterval, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel8) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel12) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbInterface, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel9) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbProtocol, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel12) + .addComponent(cmbInterface, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel7) + .addComponent(spinnerInterval, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel8) + .addComponent(jLabel9) + .addComponent(cmbProtocol, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + txtAreaLogs.setBackground(new java.awt.Color(1, 1, 1)); + txtAreaLogs.setColumns(20); + txtAreaLogs.setFont(new java.awt.Font("Courier 10 Pitch", 1, 18)); // NOI18N + txtAreaLogs.setForeground(new java.awt.Color(0, 255, 0)); + txtAreaLogs.setRows(5); + jScrollPane1.setViewportView(txtAreaLogs); + + jPanel4.setBackground(new java.awt.Color(169, 253, 173)); + + chkbxEmulate.setText("Emulate data"); + chkbxEmulate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxEmulateActionPerformed(evt); + } + }); + + cmbPeriod.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1 hour", "1 day", "1 week", "1 month " })); + cmbPeriod.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbPeriodActionPerformed(evt); + } + }); + + jLabel1.setText("Emulation Period"); + + javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addComponent(chkbxEmulate) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkbxEmulate) + .addComponent(cmbPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1)) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addComponent(lblAgentName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel8, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAgentName, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel8, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void btnControlMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnControlMouseClicked + // TODO add your handling code here: + }//GEN-LAST:event_btnControlMouseClicked + + private void btnViewMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnViewMouseClicked + // TODO add your handling code here: + }//GEN-LAST:event_btnViewMouseClicked + + private void chkbxTemperatureRandomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxTemperatureRandomActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxTemperatureRandomActionPerformed + + private void chkbxHumidityRandomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxHumidityRandomActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxHumidityRandomActionPerformed + + private void spinnerTemperatureStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerTemperatureStateChanged + // TODO add your handling code here: + }//GEN-LAST:event_spinnerTemperatureStateChanged + + private void spinnerHumidityStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerHumidityStateChanged + // TODO add your handling code here: + }//GEN-LAST:event_spinnerHumidityStateChanged + + private void txtTemperatureMinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureMinActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTemperatureMinActionPerformed + + private void txtTemperatureMaxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureMaxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTemperatureMaxActionPerformed + + private void txtHumidityMinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumidityMinActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtHumidityMinActionPerformed + + private void txtHumidityMaxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumidityMaxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtHumidityMaxActionPerformed + + private void spinnerIntervalStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerIntervalStateChanged + // TODO add your handling code here: + }//GEN-LAST:event_spinnerIntervalStateChanged + + private void cmbInterfaceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbInterfaceActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cmbInterfaceActionPerformed + + private void cmbProtocolActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbProtocolActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cmbProtocolActionPerformed + + private void txtTemperatureSVFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureSVFActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTemperatureSVFActionPerformed + + private void txtHumiditySVFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumiditySVFActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtHumiditySVFActionPerformed + + private void chkbxTemperatureSmoothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxTemperatureSmoothActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxTemperatureSmoothActionPerformed + + private void chkbxHumiditySmoothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxHumiditySmoothActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxHumiditySmoothActionPerformed + + private void cmbPeriodActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbPeriodActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cmbPeriodActionPerformed + + private void chkbxEmulateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxEmulateActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxEmulateActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnControl; + private javax.swing.JButton btnView; + private javax.swing.JCheckBox chkbxEmulate; + private javax.swing.JCheckBox chkbxHumidityRandom; + private javax.swing.JCheckBox chkbxHumiditySmooth; + private javax.swing.JCheckBox chkbxTemperatureRandom; + private javax.swing.JCheckBox chkbxTemperatureSmooth; + private javax.swing.JComboBox cmbInterface; + private javax.swing.JComboBox cmbPeriod; + private javax.swing.JComboBox cmbProtocol; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel10; + private javax.swing.JLabel jLabel11; + private javax.swing.JLabel jLabel12; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel20; + private javax.swing.JLabel jLabel23; + private javax.swing.JLabel jLabel24; + private javax.swing.JLabel jLabel25; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JLabel jLabel8; + private javax.swing.JLabel jLabel9; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JPanel jPanel6; + private javax.swing.JPanel jPanel7; + private javax.swing.JPanel jPanel8; + private javax.swing.JPanel jPanel9; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JSeparator jSeparator5; + private javax.swing.JLabel lblAgentName; + private javax.swing.JLabel lblStatus; + private javax.swing.JPanel pnlBulbStatus; + private javax.swing.JSpinner spinnerHumidity; + private javax.swing.JSpinner spinnerInterval; + private javax.swing.JSpinner spinnerTemperature; + private javax.swing.JTextArea txtAreaLogs; + private javax.swing.JTextField txtHumidityMax; + private javax.swing.JTextField txtHumidityMin; + private javax.swing.JTextField txtHumiditySVF; + private javax.swing.JTextField txtTemperatureMax; + private javax.swing.JTextField txtTemperatureMin; + private javax.swing.JTextField txtTemperatureSVF; + // End of variables declaration//GEN-END:variables +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml new file mode 100644 index 000000000..4ec107071 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/pom.xml @@ -0,0 +1,232 @@ + + + + + 4.0.0 + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl + WSO2 Carbon - IoT Server VirtualFireAlarm Agent + WSO2 Carbon - VirtualFireAlarm Device Agent Implementation + http://wso2.org + + + + + org.apache.maven.plugins + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + 2.3.2 + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.Bootstrap + + + + + jar-with-dependencies + + wso2-firealarm-virtual-agent + false + + + + make-assembly + + package + + + single + + + + + + + + + + + + + log4j + log4j + ${log4j.version} + + + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + ${paho.mqtt.version} + + + + + org.igniterealtime.smack.wso2 + smack + ${smack.wso2.version} + + + org.igniterealtime.smack.wso2 + smackx + ${smackx.wso2.version} + + + + + org.bouncycastle.wso2 + bcprov-jdk15on + ${bcprov.wso2.version} + + + org.bouncycastle.wso2 + bcpkix-jdk15on + ${bcpkix.wso2.version} + + + + + com.google.code.jscep.wso2 + jscep + ${jscep.version} + + + + commons-codec.wso2 + commons-codec + + + + commons-lang + commons-lang + ${commons-lang.version} + + + + commons-logging + commons-logging + ${common-logging.version} + + + + commons-io + commons-io + ${commons.io} + + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + org.json.wso2 + json + + + + + + + + wso2-nexus + WSO2 internal Repository + http://maven.wso2.org/nexus/content/groups/wso2-public/ + + true + daily + ignore + + + + wso2-maven2-repository + http://dist.wso2.org/maven2 + + + + + + + 1.7 + 1.7 + + + 8.1.3.v20120416 + + + 1.0.2 + + + 3.0.4.wso2v1 + 3.0.4.wso2v1 + + + 1.49.wso2v1 + 1.49.wso2v1 + + + 2.0.2.wso2v2 + + + 1.2.17 + 1.2 + 2.4 + 1.7 + 2.6 + + + 1.7.13 + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java new file mode 100644 index 000000000..63d4b2595 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/Bootstrap.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent; + +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager; + +public class Bootstrap { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); + System.setProperty("org.apache.commons.logging.simplelog.defaultlog", "info"); + System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); + System.setProperty("org.apache.commons.logging.simplelog.dateTimeFormat", "HH:mm:ss"); + AgentManager.getInstance().init(); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java new file mode 100644 index 000000000..0f920e0d0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/http/FireAlarmHTTPCommunicator.java @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.http; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.http.HTTPTransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.ProtocolException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class FireAlarmHTTPCommunicator extends HTTPTransportHandler { + private static final Log log = LogFactory.getLog(FireAlarmHTTPCommunicator.class); + + private ScheduledExecutorService service = Executors.newScheduledThreadPool(2); + private ScheduledFuture dataPushServiceHandler; + private ScheduledFuture connectorServiceHandler; + + public FireAlarmHTTPCommunicator() { + super(); + } + + public FireAlarmHTTPCommunicator(int port) { + super(port); + } + + public FireAlarmHTTPCommunicator(int port, int reconnectionInterval) { + super(port, reconnectionInterval); + } + + public ScheduledFuture getDataPushServiceHandler() { + return dataPushServiceHandler; + } + + public void connect() { + Runnable connect = new Runnable() { + public void run() { + if (!isConnected()) { + try { + processIncomingMessage(); + server.start(); + registerThisDevice(); + publishDeviceData(); + log.info("HTTP Server started at port: " + port); + + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn("Unable to 'START' HTTP server. Will retry after " + + timeoutInterval / 1000 + " seconds."); + } + } + } + } + }; + + connectorServiceHandler = service.scheduleAtFixedRate(connect, 0, timeoutInterval, + TimeUnit.MILLISECONDS); + } + + + @Override + public void processIncomingMessage() { + server.setHandler(new AbstractHandler() { + public void handle(String s, Request request, HttpServletRequest + httpServletRequest, + HttpServletResponse httpServletResponse) + throws IOException, ServletException { + httpServletResponse.setContentType("text/html;charset=utf-8"); + httpServletResponse.setStatus(HttpServletResponse.SC_OK); + request.setHandled(true); + + AgentManager agentManager = AgentManager.getInstance(); + String pathContext = request.getPathInfo(); + String separator = File.separator; + + if (pathContext.toUpperCase().contains( + separator + AgentConstants.TEMPERATURE_CONTROL)) { + httpServletResponse.getWriter().println( + agentManager.getTemperature()); + + } else if (pathContext.toUpperCase().contains( + separator + AgentConstants.HUMIDITY_CONTROL)) { + httpServletResponse.getWriter().println( + agentManager.getHumidity()); + + } else if (pathContext.toUpperCase().contains( + separator + AgentConstants.BULB_CONTROL)) { + String[] pathVariables = pathContext.split(separator); + + if (pathVariables.length != 3) { + httpServletResponse.getWriter().println( + "Invalid BULB-control received by the device. Need to be in " + + "'{host}:{port}/BULB/{ON|OFF}' format."); + return; + } + + String switchState = pathVariables[2]; + + if (switchState == null) { + httpServletResponse.getWriter().println( + "Please specify switch-status of the BULB."); + } else { + boolean status = switchState.toUpperCase().equals( + AgentConstants.CONTROL_ON); + agentManager.changeAlarmStatus(status); + httpServletResponse.getWriter().println("Bulb is " + (status ? + AgentConstants.CONTROL_ON : AgentConstants.CONTROL_OFF)); + } + } else { + httpServletResponse.getWriter().println( + "Invalid control command received by the device."); + } + } + }); + } + + @Override + public void publishDeviceData() { + final AgentManager agentManager = AgentManager.getInstance(); + int publishInterval = agentManager.getPushInterval(); + final String deviceOwner = agentManager.getAgentConfigs().getDeviceOwner(); + final String deviceID = agentManager.getAgentConfigs().getDeviceId(); + boolean simulationMode = false; + int duration = 2 * 60; + int frequency = 5; + + Runnable pushDataRunnable = new Runnable() { + @Override + public void run() { + + String pushDataPayload = String.format(AgentConstants.PUSH_DATA_PAYLOAD, deviceOwner, + deviceID, (agentManager.getDeviceIP() + ":" + port), + agentManager.getTemperature()); + executeDataPush(pushDataPayload); + } + }; + + if (!simulationMode) { + dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, + publishInterval, + TimeUnit.SECONDS); + } else { + String pushDataPayload = String.format(AgentConstants.PUSH_SIMULATION_DATA_PAYLOAD, deviceOwner, + deviceID, (agentManager.getDeviceIP() + ":" + port), + agentManager.getTemperature(), true, duration, frequency); + executeDataPush(pushDataPayload); + + } + } + + + private void executeDataPush(String pushDataPayload) { + AgentManager agentManager = AgentManager.getInstance(); + int responseCode = -1; + String pushDataEndPointURL = agentManager.getPushDataAPIEP(); + HttpURLConnection httpConnection = null; + + try { + httpConnection = TransportUtils.getHttpConnection(agentManager.getPushDataAPIEP()); + httpConnection.setRequestMethod(AgentConstants.HTTP_POST); + httpConnection.setRequestProperty("Authorization", "Bearer " + + agentManager.getAgentConfigs().getAuthToken()); + httpConnection.setRequestProperty("Content-Type", + AgentConstants.APPLICATION_JSON_TYPE); + + httpConnection.setDoOutput(true); + DataOutputStream dataOutPutWriter = new DataOutputStream( + httpConnection.getOutputStream()); + dataOutPutWriter.writeBytes(pushDataPayload); + dataOutPutWriter.flush(); + dataOutPutWriter.close(); + + responseCode = httpConnection.getResponseCode(); + httpConnection.disconnect(); + + log.info(AgentConstants.LOG_APPENDER + "Message - '" + pushDataPayload + + "' was published to server at: " + httpConnection.getURL()); + + } catch (ProtocolException exception) { + String errorMsg = + "Protocol specific error occurred when trying to set method to " + + AgentConstants.HTTP_POST + " for:" + pushDataEndPointURL; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + + } catch (IOException exception) { + String errorMsg = + "An IO error occurred whilst trying to get the response code from: " + + pushDataEndPointURL + " for a " + AgentConstants.HTTP_POST + + " " + "method."; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + + } catch (TransportHandlerException exception) { + log.error(AgentConstants.LOG_APPENDER + + "Error encountered whilst trying to create HTTP-Connection " + + "to IoT-Server EP at: " + + pushDataEndPointURL); + } + + if (responseCode == HttpStatus.CONFLICT_409 || + responseCode == HttpStatus.PRECONDITION_FAILED_412) { + log.warn(AgentConstants.LOG_APPENDER + + "DeviceIP is being Re-Registered due to Push-Data failure " + + "with response code: " + + responseCode); + registerThisDevice(); + + } else if (responseCode != HttpStatus.NO_CONTENT_204) { + if (log.isDebugEnabled()) { + log.error(AgentConstants.LOG_APPENDER + "Status Code: " + responseCode + + " encountered whilst trying to Push-Device-Data to IoT " + + "Server at: " + + agentManager.getPushDataAPIEP()); + } + agentManager.updateAgentStatus(AgentConstants.SERVER_NOT_RESPONDING); + } + + if (log.isDebugEnabled()) { + log.debug(AgentConstants.LOG_APPENDER + "Push-Data call with payload - " + + pushDataPayload + ", to IoT Server returned status " + + responseCode); + } + } + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + try { + dataPushServiceHandler.cancel(true); + connectorServiceHandler.cancel(true); + closeConnection(); + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn(AgentConstants.LOG_APPENDER + + "Unable to 'STOP' HTTP server at port: " + port); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + + "HTTP-Termination: Thread Sleep Interrupt " + + "Exception"); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage(Object message, String... messageParams) { + + } + + @Override + public void publishDeviceData(String... publishData) { + + } + + public void registerThisDevice() { + final AgentManager agentManager = AgentManager.getInstance(); + agentManager.updateAgentStatus("Registering..."); + + final Runnable ipRegistration = new Runnable() { + @Override + public void run() { + while (isConnected()) { + try { + int responseCode = registerDeviceIP( + agentManager.getAgentConfigs().getDeviceOwner(), + agentManager.getAgentConfigs().getDeviceId()); + + if (responseCode == HttpStatus.OK_200) { + agentManager.updateAgentStatus(AgentConstants.REGISTERED); + break; + } else { + log.error(AgentConstants.LOG_APPENDER + + "Device Registration with IoT Server at:" + " " + + agentManager.getIpRegistrationEP() + + " failed with response - '" + responseCode + ":" + + HttpStatus.getMessage(responseCode) + "'"); + agentManager.updateAgentStatus(AgentConstants.RETRYING_TO_REGISTER); + } + } catch (AgentCoreOperationException exception) { + log.error(AgentConstants.LOG_APPENDER + + "Error encountered whilst trying to register the " + + "Device's IP at: " + + agentManager.getIpRegistrationEP() + + ".\nCheck whether the network-interface provided is " + + "accurate"); + agentManager.updateAgentStatus(AgentConstants.REGISTRATION_FAILED); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + + "Device Registration: Thread Sleep Interrupt Exception"); + } + } + } + }; + + Thread ipRegisterThread = new Thread(ipRegistration); + ipRegisterThread.setDaemon(true); + ipRegisterThread.start(); + } + + + /** + * This method calls the "Register-API" of the IoT Server in order to register the device's IP + * against its ID. + * + * @param deviceOwner the owner of the device by whose name the agent was downloaded. + * (Read from configuration file) + * @param deviceID the deviceId that is auto-generated whilst downloading the agent. + * (Read from configuration file) + * @return the status code of the HTTP-Post call to the Register-API of the IoT-Server + * @throws AgentCoreOperationException if any errors occur when an HTTPConnection session is + * created + */ + private int registerDeviceIP(String deviceOwner, String deviceID) + throws AgentCoreOperationException { + int responseCode = -1; + final AgentManager agentManager = AgentManager.getInstance(); + + String networkInterface = agentManager.getNetworkInterface(); + String deviceIPAddress = getDeviceIP(networkInterface); + + if (deviceIPAddress == null) { + throw new AgentCoreOperationException( + "An IP address could not be retrieved for the selected network interface - '" + + networkInterface + "."); + } + + agentManager.setDeviceIP(deviceIPAddress); + log.info(AgentConstants.LOG_APPENDER + "Device IP Address: " + deviceIPAddress); + + String deviceIPRegistrationEP = agentManager.getIpRegistrationEP(); + String registerEndpointURLString = + deviceIPRegistrationEP + File.separator + deviceOwner + File.separator + deviceID + + File.separator + deviceIPAddress + File.separator + port; + + if (log.isDebugEnabled()) { + log.debug(AgentConstants.LOG_APPENDER + "DeviceIP Registration EndPoint: " + + registerEndpointURLString); + } + + HttpURLConnection httpConnection; + try { + httpConnection = TransportUtils.getHttpConnection(registerEndpointURLString); + } catch (TransportHandlerException e) { + String errorMsg = + "Protocol specific error occurred when trying to fetch an HTTPConnection to:" + + " " + + registerEndpointURLString; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(); + } + + try { + httpConnection.setRequestMethod(AgentConstants.HTTP_POST); + httpConnection.setRequestProperty("Authorization", "Bearer " + + agentManager.getAgentConfigs().getAuthToken()); + httpConnection.setDoOutput(true); + responseCode = httpConnection.getResponseCode(); + + } catch (ProtocolException exception) { + String errorMsg = "Protocol specific error occurred when trying to set method to " + + AgentConstants.HTTP_POST + " for:" + registerEndpointURLString; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, exception); + + } catch (IOException exception) { + String errorMsg = "An IO error occurred whilst trying to get the response code from:" + + " " + + registerEndpointURLString + " for a " + AgentConstants.HTTP_POST + " method."; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, exception); + } + + log.info(AgentConstants.LOG_APPENDER + "DeviceIP - " + deviceIPAddress + + ", registration with IoT Server at : " + + agentManager.getAgentConfigs().getHTTPS_ServerEndpoint() + + " returned status " + + responseCode); + + return responseCode; + } + + /*------------------------------------------------------------------------------------------*/ + /* Utility methods relevant to creating and sending HTTP requests to the Iot-Server */ + /*------------------------------------------------------------------------------------------*/ + + /** + * This method is used to get the IP of the device in which the agent is run on. + * + * @return the IP Address of the device + * @throws AgentCoreOperationException if any errors occur whilst trying to get the IP address + */ + private String getDeviceIP() throws AgentCoreOperationException { + try { + return Inet4Address.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + String errorMsg = "Error encountered whilst trying to get the device IP address."; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + } + + /** + * This is an overloaded method that fetches the public IPv4 address of the given network + * interface + * + * @param networkInterfaceName the network-interface of whose IPv4 address is to be retrieved + * @return the IP Address iof the device + * @throws AgentCoreOperationException if any errors occur whilst trying to get details of the + * given network interface + */ + private String getDeviceIP(String networkInterfaceName) throws + AgentCoreOperationException { + String ipAddress = null; + try { + Enumeration interfaceIPAddresses = NetworkInterface.getByName( + networkInterfaceName).getInetAddresses(); + for (; interfaceIPAddresses.hasMoreElements(); ) { + InetAddress ip = interfaceIPAddresses.nextElement(); + ipAddress = ip.getHostAddress(); + if (log.isDebugEnabled()) { + log.debug(AgentConstants.LOG_APPENDER + "IP Address: " + ipAddress); + } + + if (TransportUtils.validateIPv4(ipAddress)) { + return ipAddress; + } + } + } catch (SocketException | NullPointerException exception) { + String errorMsg = + "Error encountered whilst trying to get IP Addresses of the network interface: " + + networkInterfaceName + + ".\nPlease check whether the name of the network interface used is correct"; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg, exception); + } + + return ipAddress; + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java new file mode 100644 index 000000000..cb74b048b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/mqtt/FireAlarmMQTTCommunicator.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.mqtt; + +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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.mqtt.MQTTTransportHandler; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +//TODO:: Lincense heade, comments and SPECIFIC class name since its not generic +public class FireAlarmMQTTCommunicator extends MQTTTransportHandler { + + private static final Log log = LogFactory.getLog(FireAlarmMQTTCommunicator.class); + + private ScheduledExecutorService service = Executors.newScheduledThreadPool(2); + private ScheduledFuture dataPushServiceHandler; + + public FireAlarmMQTTCommunicator(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic) { + super(deviceOwner, deviceType, mqttBrokerEndPoint, subscribeTopic); + } + + @SuppressWarnings("unused") + public FireAlarmMQTTCommunicator(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic, + int intervalInMillis) { + super(deviceOwner, deviceType, mqttBrokerEndPoint, subscribeTopic, intervalInMillis); + } + + public ScheduledFuture getDataPushServiceHandler() { + return dataPushServiceHandler; + } + + //TODO:: Terminate logs with a period + //TODO: Need to print exceptions + @Override + public void connect() { + final AgentManager agentManager = AgentManager.getInstance(); + Runnable connector = new Runnable() { + public void run() { + while (!isConnected()) { + try { + connectToQueue(); + agentManager.updateAgentStatus("Connected to MQTT Queue"); + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Connection to MQTT Broker at: " + mqttBrokerEndPoint + + " failed.\n Will retry in " + timeoutInterval + " milli-seconds."); + } + + try{ + subscribeToQueue(); + agentManager.updateAgentStatus("Subscribed to MQTT Queue"); + publishDeviceData(); + + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Subscription to MQTT Broker at: " + + mqttBrokerEndPoint + " failed"); + agentManager.updateAgentStatus("Subscription to broker failed."); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException ex) { + log.error(AgentConstants.LOG_APPENDER + "MQTT: Connect-Thread Sleep Interrupt Exception."); + } + } + } + }; + + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + + @Override + public void processIncomingMessage(MqttMessage message, String... messageParams) { + final AgentManager agentManager = AgentManager.getInstance(); + String serverName = agentManager.getAgentConfigs().getServerName(); + String deviceOwner = agentManager.getAgentConfigs().getDeviceOwner(); + String deviceID = agentManager.getAgentConfigs().getDeviceId(); + String receivedMessage; + String replyMessage; + String securePayLoad; + + try { + receivedMessage = AgentUtilOperations.extractMessageFromPayload(message.toString()); + log.info(AgentConstants.LOG_APPENDER + "Message [" + receivedMessage + "] was received"); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Could not extract message from payload.", e); + return; + } + + + String[] controlSignal = receivedMessage.split(":"); + // message- ":" format.(ex: "BULB:ON", "TEMPERATURE", "HUMIDITY") + + try { + switch (controlSignal[0].toUpperCase()) { + case AgentConstants.BULB_CONTROL: + boolean stateToSwitch = controlSignal[1].equals(AgentConstants.CONTROL_ON); + agentManager.changeAlarmStatus(stateToSwitch); + log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: '" + controlSignal[1] + "'"); + break; + + case AgentConstants.TEMPERATURE_CONTROL: + int currentTemperature = agentManager.getTemperature(); + + String replyTemperature = "Current temperature was read as: '" + currentTemperature + "C'"; + log.info(AgentConstants.LOG_APPENDER + replyTemperature); + + String tempPublishTopic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, + serverName, deviceOwner, deviceID); + + replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + publishToQueue(tempPublishTopic, securePayLoad); + break; + + case AgentConstants.HUMIDITY_CONTROL: + int currentHumidity = agentManager.getHumidity(); + + String replyHumidity = "Current humidity was read as: '" + currentHumidity + "%'"; + log.info(AgentConstants.LOG_APPENDER + replyHumidity); + + String humidPublishTopic = String.format( + AgentConstants.MQTT_PUBLISH_TOPIC, serverName, deviceOwner, deviceID); + + replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + publishToQueue(humidPublishTopic, securePayLoad); + break; + + default: + log.warn(AgentConstants.LOG_APPENDER + "'" + controlSignal[0] + + "' is invalid and not-supported for this device-type"); + break; + } + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e); + } catch (TransportHandlerException e) { + log.error(AgentConstants.LOG_APPENDER + + "MQTT - Publishing, reply message to the MQTT Queue at: " + + agentManager.getAgentConfigs().getMqttBrokerEndpoint() + " failed"); + } + + } + + @Override + public void publishDeviceData() { + final AgentManager agentManager = AgentManager.getInstance(); + int publishInterval = agentManager.getPushInterval(); + Runnable pushDataRunnable = new Runnable() { + @Override + public void run() { + int currentTemperature = agentManager.getTemperature(); + String message = "PUBLISHER:" + AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + + try { + String payLoad = AgentUtilOperations.prepareSecurePayLoad(message); + + MqttMessage pushMessage = new MqttMessage(); + pushMessage.setPayload(payLoad.getBytes(StandardCharsets.UTF_8)); + pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE); + pushMessage.setRetained(false); + + String topic = String.format(AgentConstants.MQTT_PUBLISH_TOPIC, + agentManager.getAgentConfigs().getServerName(), + agentManager.getAgentConfigs().getDeviceOwner(), + agentManager.getAgentConfigs().getDeviceId()); + + publishToQueue(topic, pushMessage); + log.info(AgentConstants.LOG_APPENDER + "Message: '" + message + "' published to MQTT Queue at [" + + agentManager.getAgentConfigs().getMqttBrokerEndpoint() + "] under topic [" + + topic + "]"); + + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Data Publish attempt to topic - [" + + AgentConstants.MQTT_PUBLISH_TOPIC + "] failed for payload [" + message + "]"); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e); + } + } + }; + + dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, publishInterval, + TimeUnit.SECONDS); + } + + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + + if (dataPushServiceHandler != null) { + dataPushServiceHandler.cancel(true); + } + + try { + closeConnection(); + + } catch (MqttException e) { + if (log.isDebugEnabled()) { + log.warn(AgentConstants.LOG_APPENDER + + "Unable to 'STOP' MQTT connection at broker at: " + + mqttBrokerEndPoint); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + + "MQTT-Terminator: Thread Sleep Interrupt Exception"); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + @Override + public void processIncomingMessage() { + + } + + @Override + public void publishDeviceData(String... publishData) { + + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java new file mode 100644 index 000000000..86c4a0f7b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/communication/xmpp/FireAlarmXMPPCommunicator.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.xmpp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.packet.Message; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.xmpp.XMPPTransportHandler; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class FireAlarmXMPPCommunicator extends XMPPTransportHandler { + + private static final Log log = LogFactory.getLog(FireAlarmXMPPCommunicator.class); + + private ScheduledExecutorService service = Executors.newScheduledThreadPool(2); + private ScheduledFuture dataPushServiceHandler; + private ScheduledFuture connectorServiceHandler; + + private String username; + private String password; + private String resource; + private String xmppAdminJID; + private String xmppDeviceJID; + + public FireAlarmXMPPCommunicator(String server) { + super(server); + } + + public FireAlarmXMPPCommunicator(String server, int port) { + super(server, port); + } + + public FireAlarmXMPPCommunicator(String server, int port, int timeout) { + super(server, port, timeout); + } + + public ScheduledFuture getDataPushServiceHandler() { + return dataPushServiceHandler; + } + + @Override + public void connect() { + final AgentManager agentManager = AgentManager.getInstance(); + username = agentManager.getAgentConfigs().getDeviceId(); + password = agentManager.getAgentConfigs().getAuthToken(); + resource = agentManager.getAgentConfigs().getDeviceOwner(); + + xmppDeviceJID = username + "@" + server; + xmppAdminJID = agentManager.getAgentConfigs().getServerName() + "_" + AgentConstants.DEVICE_TYPE + "@" + server; + + + Runnable connect = new Runnable() { + public void run() { + if (!isConnected()) { + try { + connectToServer(); + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Connection to XMPP server at: " + server + " failed"); + } + + try { + loginToServer(username, password, resource); + agentManager.updateAgentStatus("Connected to XMPP Server"); + setMessageFilterAndListener(xmppAdminJID, xmppDeviceJID, true); + publishDeviceData(); + } catch (TransportHandlerException e) { + log.warn(AgentConstants.LOG_APPENDER + "Login to XMPP server at: " + server + " failed"); + agentManager.updateAgentStatus("No XMPP Account for Device"); + } + } + } + }; + + connectorServiceHandler = service.scheduleAtFixedRate(connect, 0, timeoutInterval, TimeUnit.MILLISECONDS); + } + + /** + * This is an abstract method used for post processing the received XMPP-message. This + * method will be implemented as per requirement at the time of creating an object of this + * class. + * + * @param xmppMessage the xmpp message received by the listener. + */ + @Override + public void processIncomingMessage(Message xmppMessage, String... messageParams) { + final AgentManager agentManager = AgentManager.getInstance(); + String from = xmppMessage.getFrom(); + String message = xmppMessage.getBody(); + String receivedMessage; + String replyMessage; + String securePayLoad; + + try { + receivedMessage = AgentUtilOperations.extractMessageFromPayload(message); + log.info(AgentConstants.LOG_APPENDER + "Message [" + receivedMessage + "] was received"); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Could not extract message from payload.", e); + return; + } + + String[] controlSignal = receivedMessage.split(":"); + //message- ":" format. (ex: "BULB:ON", "TEMPERATURE", "HUMIDITY") + + try { + switch (controlSignal[0].toUpperCase()) { + case AgentConstants.BULB_CONTROL: + if (controlSignal.length != 2) { + replyMessage = "BULB controls need to be in the form - 'BULB:{ON|OFF}'"; + log.warn(replyMessage); + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY"); + break; + } + + agentManager.changeAlarmStatus(controlSignal[1].equals(AgentConstants.CONTROL_ON)); + log.info(AgentConstants.LOG_APPENDER + "Bulb was switched to state: '" + controlSignal[1] + "'"); + break; + + case AgentConstants.TEMPERATURE_CONTROL: + int currentTemperature = agentManager.getTemperature(); + + String replyTemperature = + "The current temperature was read to be: '" + currentTemperature + + "C'"; + log.info(AgentConstants.LOG_APPENDER + replyTemperature); + + replyMessage = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY"); + break; + + case AgentConstants.HUMIDITY_CONTROL: + int currentHumidity = agentManager.getHumidity(); + + String replyHumidity = "The current humidity was read to be: '" + currentHumidity + "%'"; + log.info(AgentConstants.LOG_APPENDER + replyHumidity); + + replyMessage = AgentConstants.HUMIDITY_CONTROL + ":" + currentHumidity; + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-REPLY"); + break; + + default: + replyMessage = "'" + controlSignal[0] + "' is invalid and not-supported for this device-type"; + log.warn(replyMessage); + securePayLoad = AgentUtilOperations.prepareSecurePayLoad(replyMessage); + sendXMPPMessage(xmppAdminJID, securePayLoad, "CONTROL-ERROR"); + break; + } + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed", e); + } + + } + + + @Override + public void publishDeviceData() { + final AgentManager agentManager = AgentManager.getInstance(); + int publishInterval = agentManager.getPushInterval(); + + Runnable pushDataRunnable = new Runnable() { + @Override + public void run() { + Message xmppMessage = new Message(); + + try { + int currentTemperature = agentManager.getTemperature(); + + String message = AgentConstants.TEMPERATURE_CONTROL + ":" + currentTemperature; + String payLoad = AgentUtilOperations.prepareSecurePayLoad(message); + + xmppMessage.setTo(xmppAdminJID); + xmppMessage.setSubject("PUBLISHER"); + xmppMessage.setBody(payLoad); + xmppMessage.setType(Message.Type.chat); + + sendXMPPMessage(xmppAdminJID, xmppMessage); + log.info(AgentConstants.LOG_APPENDER + "Message: '" + message + "' sent to XMPP JID - " + + "[" + xmppAdminJID + "] under subject [" + xmppMessage.getSubject() + "]."); + } catch (AgentCoreOperationException e) { + log.warn(AgentConstants.LOG_APPENDER + "Preparing Secure payload failed for XMPP JID - " + + "[" + xmppAdminJID + "] with subject - [" + xmppMessage.getSubject() + "]."); + } + } + }; + + dataPushServiceHandler = service.scheduleAtFixedRate(pushDataRunnable, publishInterval, + publishInterval, TimeUnit.SECONDS); + } + + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + + if (dataPushServiceHandler != null) { + dataPushServiceHandler.cancel(true); + } + + if (connectorServiceHandler != null) { + connectorServiceHandler.cancel(true); + } + + while (isConnected()) { + closeConnection(); + + if (log.isDebugEnabled()) { + log.warn(AgentConstants.LOG_APPENDER + + "Unable to 'STOP' connection to XMPP server at: " + server); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error(AgentConstants.LOG_APPENDER + "XMPP-Terminator: Thread Sleep Interrupt Exception"); + } + + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + + @Override + public void processIncomingMessage() { + + } + + @Override + public void publishDeviceData(String... publishData) { + + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java new file mode 100644 index 000000000..e36b161cb --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConfiguration.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core; + +/** + * A Configuration class that holds all the Agent specific details that are read from the + * 'deviceConfig.properties' file. This file is generated by the IoT-Server at the time of + * downloading the device agent from the IoT-Server. + */ +public class AgentConfiguration { + private String serverName; + private String deviceOwner; + private String deviceId; + private String deviceName; + private String controllerContext; + private String HTTPS_ServerEndpoint; + private String HTTP_ServerEndpoint; + private String apimGatewayEndpoint; + private String mqttBrokerEndpoint; + private String xmppServerEndpoint; + private String authMethod; + private String authToken; + private String refreshToken; + private int dataPushInterval; + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getDeviceOwner() { + return deviceOwner; + } + + public void setDeviceOwner(String deviceOwner) { + this.deviceOwner = deviceOwner; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getControllerContext() { + return controllerContext; + } + + public void setControllerContext(String controllerContext) { + this.controllerContext = controllerContext; + } + + public String getHTTPS_ServerEndpoint() { + return HTTPS_ServerEndpoint; + } + + public void setHTTPS_ServerEndpoint(String HTTPS_ServerEndpoint) { + this.HTTPS_ServerEndpoint = HTTPS_ServerEndpoint; + } + + public String getHTTP_ServerEndpoint() { + return HTTP_ServerEndpoint; + } + + public void setHTTP_ServerEndpoint(String HTTP_ServerEndpoint) { + this.HTTP_ServerEndpoint = HTTP_ServerEndpoint; + } + + public String getApimGatewayEndpoint() { + return apimGatewayEndpoint; + } + + public void setApimGatewayEndpoint(String apimGatewayEndpoint) { + this.apimGatewayEndpoint = apimGatewayEndpoint; + } + + public String getMqttBrokerEndpoint() { + return mqttBrokerEndpoint; + } + + public void setMqttBrokerEndpoint(String mqttBrokerEndpoint) { + this.mqttBrokerEndpoint = mqttBrokerEndpoint; + } + + public String getXmppServerEndpoint() { + return xmppServerEndpoint; + } + + public void setXmppServerEndpoint(String xmppServerEndpoint) { + this.xmppServerEndpoint = xmppServerEndpoint; + } + + public String getAuthMethod() { + return authMethod; + } + + public void setAuthMethod(String authMethod) { + this.authMethod = authMethod; + } + + public String getAuthToken() { + return authToken; + } + + public void setAuthToken(String authToken) { + this.authToken = authToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public int getDataPushInterval() { + return dataPushInterval; + } + + public void setDataPushInterval(int dataPushInterval) { + this.dataPushInterval = dataPushInterval; + } +} + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java new file mode 100644 index 000000000..f415ef9e0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentConstants.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core; + +public class AgentConstants { + public static final String DEVICE_TYPE = "virtual_firealarm"; + public static final String LOG_APPENDER = "AGENT_LOG:: "; + public static final String PROPERTIES_FILE_PATH = ""; + public static final int DEFAULT_RETRY_THREAD_INTERVAL = 5000; // time in millis + /* --------------------------------------------------------------------------------------- + IoT-Server specific information + --------------------------------------------------------------------------------------- */ + public static final String DEVICE_CONTROLLER_API_EP = "/virtual_firealarm/controller"; + public static final String DEVICE_ENROLLMENT_API_EP = "/scep"; + public static final String DEVICE_REGISTER_API_EP = "/register"; + public static final String DEVICE_PUSH_TEMPERATURE_API_EP = "/temperature"; + public static final String PUSH_DATA_PAYLOAD = + "{\"owner\":\"%s\",\"deviceId\":\"%s\",\"reply\":\"%s\",\"value\":\"%s\"}"; + + public static final String PUSH_SIMULATION_DATA_PAYLOAD = + "{\"owner\":\"%s\",\"deviceId\":\"%s\",\"reply\":\"%s\",\"value\":\"%s\",\"isSimulated\":\"%s\",\"duration\":\"%s\",\"frequency\":\"%s\"}"; + + public static final String AGENT_CONTROL_APP_EP = "/devicemgt/device/%s?id=%s"; + public static final String DEVICE_DETAILS_PAGE_EP = "/devicemgt/device/%s?id=%s"; + public static final String DEVICE_ANALYTICS_PAGE_URL = "/devicemgt/analytics?deviceId=%s&deviceType=%s&deviceName=%s"; + /* --------------------------------------------------------------------------------------- + HTTP Connection specific information for communicating with IoT-Server + --------------------------------------------------------------------------------------- */ + public static final String HTTP_POST = "POST"; + public static final String HTTP_GET = "GET"; + public static final String APPLICATION_JSON_TYPE = "application/json"; + public static final String REGISTERED = "Registered"; + public static final String NOT_REGISTERED = "Not-Registered"; + public static final String REGISTRATION_FAILED = "Registration Failed"; + public static final String RETRYING_TO_REGISTER = "Registration Failed. Re-trying.."; + public static final String SERVER_NOT_RESPONDING = "Server not responding.."; + + /* --------------------------------------------------------------------------------------- + MQTT Connection specific information + --------------------------------------------------------------------------------------- */ + public static final int DEFAULT_MQTT_RECONNECTION_INTERVAL = 2; // time in seconds + public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0; + public static final String MQTT_SUBSCRIBE_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s"; + public static final String MQTT_PUBLISH_TOPIC = "%s/%s/" + DEVICE_TYPE + "/%s/publisher"; + /* --------------------------------------------------------------------------------------- + XMPP Connection specific information + --------------------------------------------------------------------------------------- */ + public static final String XMPP_ADMIN_ACCOUNT_UNAME = "admin"; + /* --------------------------------------------------------------------------------------- + Device/Agent specific properties to be read from the 'deviceConfig.properties' file + --------------------------------------------------------------------------------------- */ + public static final String AGENT_PROPERTIES_FILE_NAME = "deviceConfig.properties"; + public static final String SERVER_NAME_PROPERTY = "server-name"; + public static final String DEVICE_OWNER_PROPERTY = "owner"; + public static final String DEVICE_ID_PROPERTY = "deviceId"; + public static final String DEVICE_NAME_PROPERTY = "device-name"; + public static final String DEVICE_CONTROLLER_CONTEXT_PROPERTY = "controller-context"; + public static final String SERVER_HTTPS_EP_PROPERTY = "https-ep"; + public static final String SERVER_HTTP_EP_PROPERTY = "http-ep"; + public static final String APIM_GATEWAY_EP_PROPERTY = "apim-ep"; + public static final String MQTT_BROKER_EP_PROPERTY = "mqtt-ep"; + public static final String XMPP_SERVER_EP_PROPERTY = "xmpp-ep"; + public static final String AUTH_METHOD_PROPERTY = "auth-method"; + public static final String AUTH_TOKEN_PROPERTY = "auth-token"; + public static final String REFRESH_TOKEN_PROPERTY = "refresh-token"; + public static final String NETWORK_INTERFACE_PROPERTY = "network-interface"; + public static final String PUSH_INTERVAL_PROPERTY = "push-interval"; + /* --------------------------------------------------------------------------------------- + Default values for the Device/Agent specific configurations listed above + --------------------------------------------------------------------------------------- */ + public static final String DEFAULT_NETWORK_INTERFACE = "en0"; + public static final int DEFAULT_DATA_PUBLISH_INTERVAL = 15; // seconds + public static final String DEFAULT_PROTOCOL = "MQTT"; + /* --------------------------------------------------------------------------------------- + Control Signal specific constants to match the request context + --------------------------------------------------------------------------------------- */ + public static final String BULB_CONTROL = "BULB"; + public static final String TEMPERATURE_CONTROL = "TEMPERATURE"; + public static final String POLICY_SIGNAL = "POLICY"; + public static final String HUMIDITY_CONTROL = "HUMIDITY"; + public static final String CONTROL_ON = "ON"; + public static final String CONTROL_OFF = "OFF"; + public static final String AUDIO_FILE_NAME = "fireAlarmSound.mid"; + /* --------------------------------------------------------------------------------------- + Communication protocol specific Strings + --------------------------------------------------------------------------------------- */ + public static final String TCP_PREFIX = "tcp://"; + public static final String HTTP_PREFIX = "http://"; + public static final String HTTPS_PREFIX = "https://"; + public static final String HTTP_PROTOCOL = "HTTP"; + public static final String MQTT_PROTOCOL = "MQTT"; + public static final String XMPP_PROTOCOL = "XMPP"; +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java new file mode 100644 index 000000000..b1d204d62 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentManager.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.enrollment.EnrollmentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.http.FireAlarmHTTPCommunicator; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.mqtt.FireAlarmMQTTCommunicator; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.communication.xmpp.FireAlarmXMPPCommunicator; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.VirtualHardwareManager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AgentManager { + + private static final Log log = LogFactory.getLog(AgentManager.class); + private static AgentManager agentManager; + private String rootPath = ""; + + private boolean deviceReady = false; + private boolean isAlarmOn = false; + + private String deviceMgtControlUrl, deviceMgtAnalyticUrl; + private String deviceName, agentStatus; + + private int pushInterval; // seconds + private String prevProtocol, protocol; + + private String networkInterface; + private List interfaceList, protocolList; + private Map agentCommunicator; + + private AgentConfiguration agentConfigs; + + private String deviceIP; + private String enrollmentEP; + private String ipRegistrationEP; + private String pushDataAPIEP; + + private AgentManager() { + } + + public static AgentManager getInstance() { + if (agentManager == null) { + agentManager = new AgentManager(); + } + return agentManager; + } + + public void init() { + + agentCommunicator = new HashMap<>(); + + // Read IoT-Server specific configurations from the 'deviceConfig.properties' file + try { + this.agentConfigs = AgentUtilOperations.readIoTServerConfigs(); + } catch (AgentCoreOperationException e) { + log.error("Reading device configuration from configd file failed:\n"); + log.error(e); + System.exit(0); + } + + // Initialise IoT-Server URL endpoints from the configuration read from file + AgentUtilOperations.initializeServerEndPoints(); + + String analyticsPageContext = String.format(AgentConstants.DEVICE_ANALYTICS_PAGE_URL, + agentConfigs.getDeviceId(), + AgentConstants.DEVICE_TYPE, + agentConfigs.getDeviceName()); + + String controlPageContext = String.format(AgentConstants.DEVICE_DETAILS_PAGE_EP, + AgentConstants.DEVICE_TYPE, + agentConfigs.getDeviceId()); + + this.deviceMgtAnalyticUrl = agentConfigs.getHTTPS_ServerEndpoint() + analyticsPageContext; + this.deviceMgtControlUrl = agentConfigs.getHTTPS_ServerEndpoint() + controlPageContext; + + this.agentStatus = AgentConstants.NOT_REGISTERED; + this.deviceName = this.agentConfigs.getDeviceName(); + + this.pushInterval = this.agentConfigs.getDataPushInterval(); + this.networkInterface = AgentConstants.DEFAULT_NETWORK_INTERFACE; + + this.protocol = AgentConstants.DEFAULT_PROTOCOL; + this.prevProtocol = protocol; + + Map xmppIPPortMap; + try { + xmppIPPortMap = TransportUtils.getHostAndPort(agentConfigs.getXmppServerEndpoint()); + String xmppServer = xmppIPPortMap.get("Host"); + int xmppPort = Integer.parseInt(xmppIPPortMap.get("Port")); + + TransportHandler xmppCommunicator = new FireAlarmXMPPCommunicator(xmppServer, xmppPort); + agentCommunicator.put(AgentConstants.XMPP_PROTOCOL, xmppCommunicator); + + } catch (TransportHandlerException e) { + log.error("XMPP Endpoint String - " + agentConfigs.getXmppServerEndpoint() + + ", provided in the configuration file is invalid."); + } + String mqttTopic = String.format(AgentConstants.MQTT_SUBSCRIBE_TOPIC, + agentConfigs.getServerName(), + agentConfigs.getDeviceOwner(), + agentConfigs.getDeviceId()); + +// TransportHandler httpCommunicator = new FireAlarmHTTPCommunicator(); + TransportHandler mqttCommunicator = new FireAlarmMQTTCommunicator(agentConfigs.getDeviceOwner(), + agentConfigs.getDeviceId(), + agentConfigs.getMqttBrokerEndpoint(), + mqttTopic); + +// agentCommunicator.put(AgentConstants.HTTP_PROTOCOL, httpCommunicator); + agentCommunicator.put(AgentConstants.MQTT_PROTOCOL, mqttCommunicator); + + try { + interfaceList = new ArrayList<>(TransportUtils.getInterfaceIPMap().keySet()); + protocolList = new ArrayList<>(agentCommunicator.keySet()); + } catch (TransportHandlerException e) { + log.error("An error occurred whilst retrieving all NetworkInterface-IP mappings"); + } + + //Initializing hardware at that point + //AgentManger.setDeviceReady() method should invoked from hardware after initialization + VirtualHardwareManager.getInstance().init(); + + //Wait till hardware get ready + while (!deviceReady) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + log.info(AgentConstants.LOG_APPENDER + "Sleep error in 'device ready-flag' checking thread"); + } + } + + try { + EnrollmentManager.getInstance().beginEnrollmentFlow(); + } catch (AgentCoreOperationException e) { + log.error("Device Enrollment Failed:\n"); + log.error(e); + System.exit(0); + } + + //Start agent communication + agentCommunicator.get(protocol).connect(); + } + + private void switchCommunicator(String stopProtocol, String startProtocol) { + agentCommunicator.get(stopProtocol).disconnect(); + + while (agentCommunicator.get(stopProtocol).isConnected()) { + try { + Thread.sleep(250); + } catch (InterruptedException e) { + log.info(AgentConstants.LOG_APPENDER + + "Sleep error in 'Switch-Communicator' Thread's shutdown wait."); + } + } + + agentCommunicator.get(startProtocol).connect(); + } + + public void setInterface(int interfaceId) { + if (interfaceId != -1) { + String newInterface = interfaceList.get(interfaceId); + + if (!newInterface.equals(networkInterface)) { + networkInterface = newInterface; + + if (protocol.equals(AgentConstants.HTTP_PROTOCOL) && !protocol.equals( + prevProtocol)) { + switchCommunicator(protocol, protocol); + } + } + } + } + + public void setProtocol(int protocolId) { + if (protocolId != -1) { + String newProtocol = protocolList.get(protocolId); + + if (!protocol.equals(newProtocol)) { + prevProtocol = protocol; + protocol = newProtocol; + switchCommunicator(prevProtocol, protocol); + } + } + } + + public void changeAlarmStatus(boolean isOn) { + VirtualHardwareManager.getInstance().changeAlarmStatus(isOn); + isAlarmOn = isOn; + } + + public void updateAgentStatus(String status) { + this.agentStatus = status; + } + + /*------------------------------------------------------------------------------------------*/ + /* Getter and Setter Methods for the private variables */ + /*------------------------------------------------------------------------------------------*/ + + public void setRootPath(String rootPath) { + this.rootPath = rootPath; + } + + public void setDeviceReady(boolean deviceReady) { + this.deviceReady = deviceReady; + } + + public String getDeviceMgtControlUrl() { + return deviceMgtControlUrl; + } + + public String getDeviceMgtAnalyticUrl() { + return deviceMgtAnalyticUrl; + } + + public AgentConfiguration getAgentConfigs() { + return agentConfigs; + } + + public String getDeviceIP() { + return deviceIP; + } + + public void setDeviceIP(String deviceIP) { + this.deviceIP = deviceIP; + } + + public String getEnrollmentEP() { + return enrollmentEP; + } + + public void setEnrollmentEP(String enrollmentEP) { + this.enrollmentEP = enrollmentEP; + } + + public String getIpRegistrationEP() { + return ipRegistrationEP; + } + + public void setIpRegistrationEP(String ipRegistrationEP) { + this.ipRegistrationEP = ipRegistrationEP; + } + + public String getPushDataAPIEP() { + return pushDataAPIEP; + } + + public void setPushDataAPIEP(String pushDataAPIEP) { + this.pushDataAPIEP = pushDataAPIEP; + } + + public String getDeviceName() { + return deviceName; + } + + public String getNetworkInterface() { + return networkInterface; + } + + public String getAgentStatus() { + return agentStatus; + } + + public int getPushInterval() { + return pushInterval; + } + + public void setPushInterval(int pushInterval) { + this.pushInterval = pushInterval; + TransportHandler transportHandler = agentCommunicator.get(protocol); + + switch (protocol) { + case AgentConstants.HTTP_PROTOCOL: + ((FireAlarmHTTPCommunicator) transportHandler).getDataPushServiceHandler() + .cancel(true); + break; + case AgentConstants.MQTT_PROTOCOL: + ((FireAlarmMQTTCommunicator) transportHandler).getDataPushServiceHandler() + .cancel(true); + break; + case AgentConstants.XMPP_PROTOCOL: + ((FireAlarmXMPPCommunicator) transportHandler).getDataPushServiceHandler() + .cancel(true); + break; + default: + log.warn("Unknown protocol " + protocol); + } + transportHandler.publishDeviceData(); + + if (log.isDebugEnabled()) { + log.debug("The Data Publish Interval was changed to: " + pushInterval); + } + } + + public List getInterfaceList() { + return interfaceList; + } + + public List getProtocolList() { + return protocolList; + } + + /** + * Get temperature reading from device + * @return Temperature + */ + public int getTemperature() { + return VirtualHardwareManager.getInstance().getTemperature(); + } + + /** + * Get humidity reading from device + * @return Humidity + */ + public int getHumidity(){ + return VirtualHardwareManager.getInstance().getHumidity(); + } + + public boolean isAlarmOn() { + return isAlarmOn; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java new file mode 100644 index 000000000..d12baaa2b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/core/AgentUtilOperations.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.enrollment.EnrollmentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.CommunicationUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Properties; + +/** + * This class contains all the core operations of the FireAlarm agent that are common to both + * Virtual and Real Scenarios. These operations include, connecting to and subscribing to an MQTT + * queue and to a XMPP Server. Pushing temperature data to the IoT-Server at timely intervals. + * Reading device specific configuration from a configs file etc.... + */ +public class AgentUtilOperations { + + private static final Log log = LogFactory.getLog(AgentUtilOperations.class); + private static final String JSON_MESSAGE_KEY = "Msg"; + private static final String JSON_SIGNATURE_KEY = "Sig"; + + /** + * This method reads the agent specific configurations for the device from the + * "deviceConfigs.properties" file found at /repository/conf folder. + * If the properties file is not found in the specified path, then the configuration values + * are set to the default ones in the 'AgentConstants' class. + * + * @return an object of type 'AgentConfiguration' which contains all the necessary + * configuration attributes + */ + public static AgentConfiguration readIoTServerConfigs() throws AgentCoreOperationException { + AgentManager agentManager = AgentManager.getInstance(); + AgentConfiguration iotServerConfigs = new AgentConfiguration(); + Properties properties = new Properties(); + InputStream propertiesInputStream = null; + String propertiesFileName = AgentConstants.AGENT_PROPERTIES_FILE_NAME; + + try { + ClassLoader loader = AgentUtilOperations.class.getClassLoader(); + URL path = loader.getResource(propertiesFileName); + System.out.println(path); + String root = path.getPath().replace("wso2-firealarm-virtual-agent.jar!/deviceConfig.properties", "") + .replace("jar:", "").replace("file:", ""); + + root = URLDecoder.decode(root, StandardCharsets.UTF_8.toString()); + agentManager.setRootPath(root); + + String deviceConfigFilePath = root + AgentConstants.AGENT_PROPERTIES_FILE_NAME; + propertiesInputStream = new FileInputStream(deviceConfigFilePath); + + //load a properties file from class path, inside static method + properties.load(propertiesInputStream); + + iotServerConfigs.setServerName(properties.getProperty( + AgentConstants.SERVER_NAME_PROPERTY)); + iotServerConfigs.setDeviceOwner(properties.getProperty( + AgentConstants.DEVICE_OWNER_PROPERTY)); + iotServerConfigs.setDeviceId(properties.getProperty( + AgentConstants.DEVICE_ID_PROPERTY)); + iotServerConfigs.setDeviceName(properties.getProperty( + AgentConstants.DEVICE_NAME_PROPERTY)); + iotServerConfigs.setControllerContext(properties.getProperty( + AgentConstants.DEVICE_CONTROLLER_CONTEXT_PROPERTY)); + iotServerConfigs.setHTTPS_ServerEndpoint(properties.getProperty( + AgentConstants.SERVER_HTTPS_EP_PROPERTY)); + iotServerConfigs.setHTTP_ServerEndpoint(properties.getProperty( + AgentConstants.SERVER_HTTP_EP_PROPERTY)); + iotServerConfigs.setApimGatewayEndpoint(properties.getProperty( + AgentConstants.APIM_GATEWAY_EP_PROPERTY)); + iotServerConfigs.setMqttBrokerEndpoint(properties.getProperty( + AgentConstants.MQTT_BROKER_EP_PROPERTY)); + iotServerConfigs.setXmppServerEndpoint(properties.getProperty( + AgentConstants.XMPP_SERVER_EP_PROPERTY)); + iotServerConfigs.setAuthMethod(properties.getProperty( + AgentConstants.AUTH_METHOD_PROPERTY)); + iotServerConfigs.setAuthToken(properties.getProperty( + AgentConstants.AUTH_TOKEN_PROPERTY)); + iotServerConfigs.setRefreshToken(properties.getProperty( + AgentConstants.REFRESH_TOKEN_PROPERTY)); + iotServerConfigs.setDataPushInterval(Integer.parseInt(properties.getProperty( + AgentConstants.PUSH_INTERVAL_PROPERTY))); + + log.info(AgentConstants.LOG_APPENDER + "Server name: " + + iotServerConfigs.getServerName()); + log.info(AgentConstants.LOG_APPENDER + "Device Owner: " + + iotServerConfigs.getDeviceOwner()); + log.info(AgentConstants.LOG_APPENDER + "Device ID: " + iotServerConfigs.getDeviceId()); + log.info(AgentConstants.LOG_APPENDER + "Device Name: " + + iotServerConfigs.getDeviceName()); + log.info(AgentConstants.LOG_APPENDER + "Device Controller Context: " + + iotServerConfigs.getControllerContext()); + log.info(AgentConstants.LOG_APPENDER + "IoT Server HTTPS EndPoint: " + + iotServerConfigs.getHTTPS_ServerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "IoT Server HTTP EndPoint: " + + iotServerConfigs.getHTTP_ServerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "API-Manager Gateway EndPoint: " + + iotServerConfigs.getApimGatewayEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "MQTT Broker EndPoint: " + + iotServerConfigs.getMqttBrokerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "XMPP Server EndPoint: " + + iotServerConfigs.getXmppServerEndpoint()); + log.info(AgentConstants.LOG_APPENDER + "Authentication Method: " + + iotServerConfigs.getAuthMethod()); + log.info(AgentConstants.LOG_APPENDER + "Authentication Token: " + + iotServerConfigs.getAuthToken()); + log.info(AgentConstants.LOG_APPENDER + "Refresh Token: " + + iotServerConfigs.getRefreshToken()); + log.info(AgentConstants.LOG_APPENDER + "Data Push Interval: " + + iotServerConfigs.getDataPushInterval()); + + } catch (FileNotFoundException ex) { + String errorMsg = "[" + propertiesFileName + "] file not found at: " + AgentConstants.PROPERTIES_FILE_PATH; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg); + + } catch (IOException ex) { + String errorMsg = "Error occurred whilst trying to fetch [" + propertiesFileName + "] from: " + + AgentConstants.PROPERTIES_FILE_PATH; + log.error(AgentConstants.LOG_APPENDER + errorMsg); + throw new AgentCoreOperationException(errorMsg); + } finally { + if (propertiesInputStream != null) { + try { + propertiesInputStream.close(); + } catch (IOException e) { + log.error(AgentConstants.LOG_APPENDER + + "Error occurred whilst trying to close InputStream resource used to read the '" + + propertiesFileName + "' file"); + } + } + } + return iotServerConfigs; + } + + /** + * This method constructs the URLs for each of the API Endpoints called by the device agent + * Ex: Register API, Push-Data API + * + * @throws AgentCoreOperationException if any error occurs at socket level whilst trying to + * retrieve the deviceIP of the network-interface read + * from the configs file + */ + public static void initializeServerEndPoints() { + AgentManager agentManager = AgentManager.getInstance(); + String serverSecureEndpoint = agentManager.getAgentConfigs().getHTTPS_ServerEndpoint(); + String serverUnSecureEndpoint = agentManager.getAgentConfigs().getHTTP_ServerEndpoint(); + String backEndContext = agentManager.getAgentConfigs().getControllerContext(); + + String deviceControllerAPIEndpoint = serverSecureEndpoint + backEndContext; + + String deviceEnrollmentEndpoint = + serverUnSecureEndpoint + backEndContext + AgentConstants.DEVICE_ENROLLMENT_API_EP; + agentManager.setEnrollmentEP(deviceEnrollmentEndpoint); + + String registerEndpointURL = + deviceControllerAPIEndpoint + AgentConstants.DEVICE_REGISTER_API_EP; + agentManager.setIpRegistrationEP(registerEndpointURL); + + String pushDataEndPointURL = + deviceControllerAPIEndpoint + AgentConstants.DEVICE_PUSH_TEMPERATURE_API_EP; + agentManager.setPushDataAPIEP(pushDataEndPointURL); + + log.info(AgentConstants.LOG_APPENDER + "IoT Server's Device Controller API Endpoint: " + + deviceControllerAPIEndpoint); + log.info(AgentConstants.LOG_APPENDER + "Device Enrollment EndPoint: " + + registerEndpointURL); + log.info(AgentConstants.LOG_APPENDER + "DeviceIP Registration EndPoint: " + + registerEndpointURL); + log.info(AgentConstants.LOG_APPENDER + "Push-Data API EndPoint: " + pushDataEndPointURL); + } + + + public static String prepareSecurePayLoad(String message) throws AgentCoreOperationException { + PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey(); + PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey(); + + String encryptedMsg; + try { + encryptedMsg = CommunicationUtils.encryptMessage(message, serverPublicKey); + } catch (TransportHandlerException e) { + String errorMsg = "Error occurred whilst trying to encryptMessage: [" + message + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + String signedPayload; + try { + signedPayload = CommunicationUtils.signMessage(encryptedMsg, devicePrivateKey); + } catch (TransportHandlerException e) { + String errorMsg = "Error occurred whilst trying to sign encrypted message of: [" + message + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + JSONObject jsonPayload = new JSONObject(); + jsonPayload.put(JSON_MESSAGE_KEY, encryptedMsg); + jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload); + + return jsonPayload.toString(); + } + + + public static String extractMessageFromPayload(String message) throws AgentCoreOperationException { + String actualMessage; + + PublicKey serverPublicKey = EnrollmentManager.getInstance().getServerPublicKey(); + PrivateKey devicePrivateKey = EnrollmentManager.getInstance().getPrivateKey(); + + JSONObject jsonPayload = new JSONObject(message); + Object encryptedMessage = jsonPayload.get(JSON_MESSAGE_KEY); + Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY); + boolean verification; + + if (encryptedMessage != null && signedPayload != null) { + try { + verification = CommunicationUtils.verifySignature( + encryptedMessage.toString(), signedPayload.toString(), serverPublicKey); + } catch (TransportHandlerException e) { + String errorMsg = + "Error occurred whilst trying to verify signature on received message: [" + message + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + } else { + String errorMsg = "The received message is in an INVALID format. " + + "Need to be JSON - {\"Msg\":\"\", \"Sig\":\"\"}."; + throw new AgentCoreOperationException(errorMsg); + } + + try { + if (verification) { + actualMessage = CommunicationUtils.decryptMessage(encryptedMessage.toString(), devicePrivateKey); + } else { + String errorMsg = "Could not verify payload signature. The message was not signed by a valid client"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg); + } + } catch (TransportHandlerException e) { + String errorMsg = "Error occurred whilst trying to decrypt received message: [" + encryptedMessage + "]"; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return actualMessage; + } + + +} + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java new file mode 100644 index 000000000..a4347cbae --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/enrollment/EnrollmentManager.java @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.enrollment; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; +import org.jscep.client.Client; +import org.jscep.client.ClientException; +import org.jscep.client.EnrollmentResponse; +import org.jscep.client.verification.CertificateVerifier; +import org.jscep.client.verification.OptimisticCertificateVerifier; +import org.jscep.transaction.TransactionException; +import org.jscep.transport.response.Capabilities; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception.AgentCoreOperationException; +import sun.security.x509.X509CertImpl; + +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; + +/** + * This class controls the entire SCEP enrolment process of the client. It is a singleton for any single client which + * has the agent code running in it. The main functionality of this class includes generating a Private-Public Key + * Pair for the enrollment flow, creating the Certificate-Sign-Request using the generated Public-Key to send to the + * SEP server, Contacting the SCEP server to receive the Signed Certificate and requesting for the server's public + * key for encrypting the payloads. + * The provider for all Cryptographic functions used in this class are "BouncyCastle" and the Asymmetric-Key pair + * algorithm used is "RSA" with a key size of 2048. The signature algorithm used is "SHA1withRSA". + * This class also holds the "SCEPUrl" (Server Url read from the configs file), the Private-Public Keys of the + * client, Signed SCEP certificate and the server's public certificate. + */ + +//TODO: Need to save cert and keys to file after initial enrollment... +public class EnrollmentManager { + private static final Log log = LogFactory.getLog(EnrollmentManager.class); + private static EnrollmentManager enrollmentManager; + + private static final String KEY_PAIR_ALGORITHM = "RSA"; + private static final String PROVIDER = "BC"; + private static final String SIGNATURE_ALG = "SHA1withRSA"; + private static final int KEY_SIZE = 2048; + + // Seed to our PRNG. Make sure this is initialised randomly, NOT LIKE THIS + private static final byte[] SEED = ")(*&^%$#@!".getBytes(); + private static final int CERT_VALIDITY = 730; + + // URL of our SCEP server + private String SCEPUrl; + private PrivateKey privateKey; + private PublicKey publicKey; + private PublicKey serverPublicKey; + private X509Certificate SCEPCertificate; + + + /** + * Constructor of the EnrollmentManager. Initializes the SCEPUrl as read from the configuration file by the + * AgentManager. + */ + private EnrollmentManager() { + this.SCEPUrl = AgentManager.getInstance().getEnrollmentEP(); + } + + /** + * Method to return the current singleton instance of the EnrollmentManager. + * + * @return the current singleton instance if available and if not initializes a new instance and returns it. + */ + public static EnrollmentManager getInstance() { + if (enrollmentManager == null) { + enrollmentManager = new EnrollmentManager(); + } + return enrollmentManager; + } + + + /** + * Method to control the entire enrollment flow. This method calls the method to create the Private-Public Key + * Pair, calls the specific method to generate the Certificate-Sign-Request, creates a one time self signed + * certificate to present to the SCEP server with the initial CSR, calls the specific method to connect to the + * SCEP Server and to get the SCEP Certificate and also calls the method that requests the SCEP Server for its + * PublicKey for future payload encryption. + * + * @throws AgentCoreOperationException if the private method generateCertSignRequest() fails with an error or if + * there is an error creating a self-sign certificate to present to the + * server (whilst trying to get the CSR signed) + */ + public void beginEnrollmentFlow() throws AgentCoreOperationException { + Security.addProvider(new BouncyCastleProvider()); + + KeyPair keyPair = generateKeyPair(); + this.privateKey = keyPair.getPrivate(); + this.publicKey = keyPair.getPublic(); + + if (log.isDebugEnabled()) { + log.info(AgentConstants.LOG_APPENDER + "DevicePrivateKey:\n[\n" + privateKey + "\n]\n"); + log.info(AgentConstants.LOG_APPENDER + "DevicePublicKey:\n[\n" + publicKey + "\n]\n"); + } + + PKCS10CertificationRequest certSignRequest = generateCertSignRequest(); + + /** + * ----------------------------------------------------------------------------------------------- + * Generate an ephemeral self-signed certificate. This is needed to present to the CA in the SCEP request. + * In the future, add proper EKU and attributes in the request. The CA does NOT have to honour any of this. + * ----------------------------------------------------------------------------------------------- + */ + X500Name issuer = new X500Name("CN=Temporary Issuer"); + BigInteger serial = new BigInteger(32, new SecureRandom()); + Date fromDate = new Date(); + Date toDate = new Date(System.currentTimeMillis() + (CERT_VALIDITY * 86400000L)); + + // Build the self-signed cert using BC, sign it with our private key (self-signed) + X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuer, serial, fromDate, toDate, + certSignRequest.getSubject(), + certSignRequest.getSubjectPublicKeyInfo()); + ContentSigner sigGen; + X509Certificate tmpCert; + + try { + sigGen = new JcaContentSignerBuilder(SIGNATURE_ALG).setProvider(PROVIDER).build(keyPair.getPrivate()); + tmpCert = new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certBuilder.build(sigGen)); + } catch (OperatorCreationException e) { + String errorMsg = "Error occurred whilst creating a ContentSigner for the Temp-Self-Signed Certificate."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (CertificateException e) { + String errorMsg = "Error occurred whilst trying to create Temp-Self-Signed Certificate."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + /** + * ----------------------------------------------------------------------------------------------- + */ + + this.SCEPCertificate = getSignedCertificateFromServer(tmpCert, certSignRequest); + this.serverPublicKey = initPublicKeyOfServer(); + + if (log.isDebugEnabled()) { + log.info(AgentConstants.LOG_APPENDER + "TemporaryCertPublicKey:\n[\n" + tmpCert.getPublicKey() + "\n]\n"); + log.info(AgentConstants.LOG_APPENDER + "ServerPublicKey:\n[\n" + serverPublicKey + "\n]\n"); + } + + } + + + /** + * This method creates the Public-Private Key pair for the current client. + * + * @return the generated KeyPair object + * @throws AgentCoreOperationException when the given Security Provider does not exist or the Algorithmn used to + * generate the key pair is invalid. + */ + private KeyPair generateKeyPair() throws AgentCoreOperationException { + + // Generate key pair + KeyPairGenerator keyPairGenerator; + try { + keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM, PROVIDER); + keyPairGenerator.initialize(KEY_SIZE, new SecureRandom(SEED)); + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm [" + KEY_PAIR_ALGORITHM + "] provided for KeyPairGenerator is invalid."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (NoSuchProviderException e) { + String errorMsg = "Provider [" + PROVIDER + "] provided for KeyPairGenerator does not exist."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return keyPairGenerator.genKeyPair(); + } + + + /** + * This method creates the PKCS10 Certificate Sign Request which is to be sent to the SCEP Server using the + * generated PublicKey of the client. The certificate parameters used here are the ones from the AgentManager + * which are the values read from the configurations file. + * + * @return the PKCS10CertificationRequest object created using the client specific configs and the generated + * PublicKey + * @throws AgentCoreOperationException if an error occurs when creating a content signer to sign the CSR. + */ + private PKCS10CertificationRequest generateCertSignRequest() throws AgentCoreOperationException { + // Build the CN for the cert that's being requested. + X500NameBuilder nameBld = new X500NameBuilder(BCStyle.INSTANCE); + nameBld.addRDN(BCStyle.CN, AgentManager.getInstance().getAgentConfigs().getServerName()); + nameBld.addRDN(BCStyle.O, AgentManager.getInstance().getAgentConfigs().getDeviceOwner()); + nameBld.addRDN(BCStyle.OU, AgentManager.getInstance().getAgentConfigs().getDeviceOwner()); + nameBld.addRDN(BCStyle.UNIQUE_IDENTIFIER, AgentManager.getInstance().getAgentConfigs().getDeviceId()); + nameBld.addRDN(BCStyle.SERIALNUMBER, AgentManager.getInstance().getAgentConfigs().getDeviceId()); + X500Name principal = nameBld.build(); + + JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGNATURE_ALG).setProvider(PROVIDER); + ContentSigner contentSigner; + + try { + contentSigner = contentSignerBuilder.build(this.privateKey); + } catch (OperatorCreationException e) { + String errorMsg = "Could not create content signer with private key."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + // Generate the certificate signing request (csr = PKCS10) + PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(principal, + this.publicKey); + return reqBuilder.build(contentSigner); + } + + + /** + * This method connects to the SCEP Server to fetch the signed SCEP Certificate. + * + * @param tempCert the temporary self-signed certificate of the client required for the initial CSR + * request against the SCEP Server. + * @param certSignRequest the PKCS10 Certificate-Sign-Request that is to be sent to the SCEP Server. + * @return the SCEP-Certificate for the client signed by the SCEP-Server. + * @throws AgentCoreOperationException if the SCEPUrl is invalid or if the flow of sending the CSR and getting + * the signed certificate fails or if the signed certificate cannot be + * retrieved from the reply from the server. + */ + private X509Certificate getSignedCertificateFromServer(X509Certificate tempCert, + PKCS10CertificationRequest certSignRequest) + throws AgentCoreOperationException { + + X509Certificate signedSCEPCertificate = null; + URL url; + EnrollmentResponse enrolResponse; + CertStore certStore; + + try { + // The URL where we are going to request our cert from + url = new URL(this.SCEPUrl); + + /* // This is called when we get the certificate for our CSR signed by CA + // Implement this handler to check the CA cert in prod. We can do cert pinning here + CallbackHandler cb = new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated + methods, choose Tools | Templates. + } + };*/ + + // Implement verification of the CA cert. VERIFY the CA + CertificateVerifier ocv = new OptimisticCertificateVerifier(); + + // Instantiate our SCEP client + Client scepClient = new Client(url, ocv); + + // Submit our cert for signing. SCEP server should allow the client to specify + // the SCEP CA to issue the request against, if there are multiple CAs + enrolResponse = scepClient.enrol(tempCert, this.privateKey, certSignRequest); + + // Verify we got what we want, and just print out the cert. + certStore = enrolResponse.getCertStore(); + + for (Certificate x509Certificate : certStore.getCertificates(null)) { + if (log.isDebugEnabled()) { + log.debug(x509Certificate.toString()); + } + signedSCEPCertificate = (X509Certificate) x509Certificate; + } + + } catch (MalformedURLException ex) { + String errorMsg = "Could not create valid URL from given SCEP URI: " + SCEPUrl; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, ex); + } catch (TransactionException | ClientException e) { + String errorMsg = "Enrollment process to SCEP Server at: " + SCEPUrl + " failed."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (CertStoreException e) { + String errorMsg = "Could not retrieve [Signed-Certificate] from the response message from SCEP-Server."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return signedSCEPCertificate; + } + + + /** + * Gets the Public Key of the SCEP-Server and initializes it for later use. This method contacts the SCEP Server + * and fetches its CA Cert and extracts the Public Key of the server from the received reply. + * + * @return the public key of the SCEP Server which is to be used to encrypt pyloads. + * @throws AgentCoreOperationException if the SCEPUrl is invalid or if the flow of sending the CSR and getting + * the signed certificate fails or if the signed certificate cannot be + * retrieved from the reply from the server. + */ + private PublicKey initPublicKeyOfServer() throws AgentCoreOperationException { + URL url; + CertStore certStore; + PublicKey serverCertPublicKey = null; + + try { + // The URL where we are going to request our cert from + url = new URL(this.SCEPUrl); + + /* // This is called when we get the certificate for our CSR signed by CA + // Implement this handler to check the CA cert in prod. We can do cert pinning here + CallbackHandler cb = new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated + methods, choose Tools | Templates. + } + };*/ + + // Implement verification of the CA cert. VERIFY the CA + CertificateVerifier ocv = new OptimisticCertificateVerifier(); + + // Instantiate our SCEP client + Client scepClient = new Client(url, ocv); + + // Get the CA capabilities. Should return SHA1withRSA for strongest hash and sig. Returns MD5. + if (log.isDebugEnabled()) { + Capabilities cap = scepClient.getCaCapabilities(); + log.debug(String.format( + "\nStrongestCipher: %s,\nStrongestMessageDigest: %s,\nStrongestSignatureAlgorithm: %s," + + "\nIsRenewalSupported: %s,\nIsRolloverSupported: %s", + cap.getStrongestCipher(), cap.getStrongestMessageDigest(), cap.getStrongestSignatureAlgorithm(), + cap.isRenewalSupported(), cap.isRolloverSupported())); + } + + certStore = scepClient.getCaCertificate(); + + for (Certificate cert : certStore.getCertificates(null)) { + if (cert instanceof X509Certificate) { + if (log.isDebugEnabled()) { + log.debug(((X509Certificate) cert).getIssuerDN().getName()); + } + + //TODO: Need to identify the correct certificate. + // I have chosen the CA cert based on its BasicConstraint criticality being set to "true" + if (((X509CertImpl) cert).getBasicConstraintsExtension().isCritical()) { + serverCertPublicKey = cert.getPublicKey(); + } + } + } + + } catch (MalformedURLException ex) { + String errorMsg = "Could not create valid URL from given SCEP URI: " + SCEPUrl; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, ex); + } catch (ClientException e) { + String errorMsg = "Could not retrieve [Server-Certificate] from the SCEP-Server."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } catch (CertStoreException e) { + String errorMsg = "Could not retrieve [Server-Certificates] from the response message from SCEP-Server."; + log.error(errorMsg); + throw new AgentCoreOperationException(errorMsg, e); + } + + return serverCertPublicKey; + } + + + /** + * Gets the Public-Key of the client. + * @return the public key of the client. + */ + public PublicKey getPublicKey() { + return publicKey; + } + + /** + * Gets the Private-Key of the client. + * @return the private key of the client. + */ + public PrivateKey getPrivateKey() { + return privateKey; + } + + /** + * Gets the SCEP-Certificate of the client. + * @return the SCEP Certificate of the client. + */ + public X509Certificate getSCEPCertificate() { + return SCEPCertificate; + } + + /** + * Gets the Public-Key of the Server. + * @return the pubic key of the server. + */ + public PublicKey getServerPublicKey() { + return serverPublicKey; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java new file mode 100644 index 000000000..fac321ef9 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/exception/AgentCoreOperationException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.exception; + + +public class AgentCoreOperationException extends Exception{ + private static final long serialVersionUID = 2736466230451105710L; + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public AgentCoreOperationException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public AgentCoreOperationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public AgentCoreOperationException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public AgentCoreOperationException() { + super(); + } + + public AgentCoreOperationException(Throwable cause) { + super(cause); + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java new file mode 100644 index 000000000..bb445a3d9 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/CommunicationUtils.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; + +/** + * This is a utility class which contains methods common to the communication process of a client and the server. The + * methods include encryption/decryption of payloads and signing/verification of payloads received and to be sent. + */ +public class CommunicationUtils { + private static final Log log = LogFactory.getLog(TransportUtils.class); + + // The Signature Algorithm used. + private static final String SIGNATURE_ALG = "SHA1withRSA"; + // The Encryption Algorithm and the Padding used. + private static final String CIPHER_PADDING = "RSA/ECB/PKCS1Padding"; + + + /** + * Encrypts the message with the key that's passed in. + * + * @param message the message to be encrypted. + * @param encryptionKey the key to use for the encryption of the message. + * @return the encrypted message in String format. + * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding + * issues, encryption key being invalid or the algorithm used is unrecognizable. + */ + public static String encryptMessage(String message, Key encryptionKey) throws TransportHandlerException { + Cipher encrypter; + byte[] cipherData; + + try { + encrypter = Cipher.getInstance(CIPHER_PADDING); + encrypter.init(Cipher.ENCRYPT_MODE, encryptionKey); + cipherData = encrypter.doFinal(message.getBytes(StandardCharsets.UTF_8)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + encryptionKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return Base64.encodeBase64String(cipherData); + } + +///TODO:: Exception needs to change according to the common package + /** + * Signed a given message using the PrivateKey that's passes in. + * + * @param message the message to be signed. Ideally some encrypted payload. + * @param signatureKey the PrivateKey with which the message is to be signed. + * @return the Base64Encoded String of the signed payload. + * @throws TransportHandlerException if some error occurs with the signing process which may be related to the + * signature algorithm used or the key used for signing. + */ + public static String signMessage(String message, PrivateKey signatureKey) throws TransportHandlerException { + + Signature signature; + String signedEncodedString; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initSign(signatureKey); + signature.update(Base64.decodeBase64(message)); + + byte[] signatureBytes = signature.sign(); + signedEncodedString = Base64.encodeBase64String(signatureBytes); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = + "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + signatureKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return signedEncodedString; + } + + + /** + * Verifies some signed-data against the a Public-Key to ensure that it was produced by the holder of the + * corresponding Private Key. + * + * @param data the actual payoad which was signed by some Private Key. + * @param signedData the signed data produced by signing the payload using a Private Key. + * @param verificationKey the corresponding Public Key which is an exact pair of the Private-Key with we expect + * the data to be signed by. + * @return true if the signed data verifies to be signed by the corresponding Private Key. + * @throws TransportHandlerException if some error occurs with the verification process which may be related to + * the signature algorithm used or the key used for signing. + */ + public static boolean verifySignature(String data, String signedData, PublicKey verificationKey) + throws TransportHandlerException { + + Signature signature; + boolean verified; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initVerify(verificationKey); + signature.update(Base64.decodeBase64(data)); + + verified = signature.verify(Base64.decodeBase64(signedData)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = + "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + verificationKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return verified; + } + + + /** + * Encrypts the message with the key that's passed in. + * + * @param encryptedMessage the encrypted message that is supposed to be decrypted. + * @param decryptKey the key to use in the decryption process. + * @return the decrypted message in String format. + * @throws TransportHandlerException if an error occurs with the encryption flow which can be due to Padding + * issues, encryption key being invalid or the algorithm used is unrecognizable. + */ + public static String decryptMessage(String encryptedMessage, Key decryptKey) throws TransportHandlerException { + + Cipher decrypter; + String decryptedMessage; + + try { + + decrypter = Cipher.getInstance(CIPHER_PADDING); + decrypter.init(Cipher.DECRYPT_MODE, decryptKey); + decryptedMessage = new String(decrypter.doFinal(Base64.decodeBase64(encryptedMessage)), + StandardCharsets.UTF_8); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + decryptKey + "\n]\n"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + + return decryptedMessage; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java new file mode 100644 index 000000000..fa45cdbb0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport; + +/** + * This interface consists of the core functionality related to the transport between any device and the server. The + * interface is an abstraction, regardless of the underlying protocol used for the transport. Implementation of this + * interface by any class that caters a specific protocol (ex: HTTP, XMPP, MQTT, CoAP) would ideally have methods + * specific to the protocol used for communication and thees methods that implement the logic related to the devices + * using the protocol. + * + * @param a message type specific to the protocol implemented + */ +public interface TransportHandler { + int DEFAULT_TIMEOUT_INTERVAL = 5000; // millis ~ 10 sec + + void connect(); + + boolean isConnected(); + + //TODO:: Any errors needs to be thrown ahead + void processIncomingMessage(T message, String... messageParams); + + void processIncomingMessage(); + + void publishDeviceData(String... publishData); + + void publishDeviceData(); + + void disconnect(); +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java new file mode 100644 index 000000000..9ae69a998 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportHandlerException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport; + +public class TransportHandlerException extends Exception { + private static final long serialVersionUID = 2736466230451105440L; + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public TransportHandlerException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public TransportHandlerException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public TransportHandlerException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public TransportHandlerException() { + super(); + } + + public TransportHandlerException(Throwable cause) { + super(cause); + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java new file mode 100644 index 000000000..a5c20bbf0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/TransportUtils.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.DatagramSocket; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.SocketException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class TransportUtils { + private static final Log log = LogFactory.getLog(TransportUtils.class); + + public static final int MIN_PORT_NUMBER = 9000; + public static final int MAX_PORT_NUMBER = 11000; + + /** + * Given a server endpoint as a String, this method splits it into Protocol, Host and Port + * + * @param ipString a network endpoint in the format - '://:' + * @return a map with keys "Protocol", "Host" & "Port" for the related values from the ipString + * @throws TransportHandlerException + */ + public static Map getHostAndPort(String ipString) + throws TransportHandlerException { + Map ipPortMap = new HashMap(); + String[] ipPortArray = ipString.split(":"); + + if (ipPortArray.length != 3) { + String errorMsg = + "The IP String - '" + ipString + + "' is invalid. It needs to be in format '://:'."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg); + } + + ipPortMap.put("Protocol", ipPortArray[0]); + ipPortMap.put("Host", ipPortArray[1].replace(File.separator, "")); + ipPortMap.put("Port", ipPortArray[2]); + return ipPortMap; + } + + /** + * This method validates whether a specific IP Address is of IPv4 type + * + * @param ipAddress the IP Address which needs to be validated + * @return true if it is of IPv4 type and false otherwise + */ + public static boolean validateIPv4(String ipAddress) { + try { + if (ipAddress == null || ipAddress.isEmpty()) { + return false; + } + + String[] parts = ipAddress.split("\\."); + if (parts.length != 4) { + return false; + } + + for (String s : parts) { + int i = Integer.parseInt(s); + if ((i < 0) || (i > 255)) { + return false; + } + } + return !ipAddress.endsWith("."); + + } catch (NumberFormatException nfe) { + log.warn("The IP Address: " + ipAddress + " could not " + + "be validated against IPv4-style"); + return false; + } + } + + + public static Map getInterfaceIPMap() throws TransportHandlerException { + + Map interfaceToIPMap = new HashMap(); + Enumeration networkInterfaces; + String networkInterfaceName = ""; + String ipAddress; + + try { + networkInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException exception) { + String errorMsg = + "Error encountered whilst trying to get the list of network-interfaces"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + try { + for (; networkInterfaces.hasMoreElements(); ) { + networkInterfaceName = networkInterfaces.nextElement().getName(); + + if (log.isDebugEnabled()) { + log.debug("Network Interface: " + networkInterfaceName); + log.debug("------------------------------------------"); + } + + Enumeration interfaceIPAddresses = NetworkInterface.getByName( + networkInterfaceName).getInetAddresses(); + + for (; interfaceIPAddresses.hasMoreElements(); ) { + ipAddress = interfaceIPAddresses.nextElement().getHostAddress(); + + if (log.isDebugEnabled()) { + log.debug("IP Address: " + ipAddress); + } + + if (TransportUtils.validateIPv4(ipAddress)) { + interfaceToIPMap.put(networkInterfaceName, ipAddress); + } + } + + if (log.isDebugEnabled()) { + log.debug("------------------------------------------"); + } + } + } catch (SocketException exception) { + String errorMsg = + "Error encountered whilst trying to get the IP Addresses of the network " + + "interface: " + networkInterfaceName; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + return interfaceToIPMap; + } + + + /** + * Attempts to find a free port between the MIN_PORT_NUMBER(9000) and MAX_PORT_NUMBER(11000). + * Tries 'RANDOMLY picked' port numbers between this range up-until "randomAttempts" number of + * times. If still fails, then tries each port in descending order from the MAX_PORT_NUMBER + * whilst skipping already attempted ones via random selection. + * + * @param randomAttempts no of times to TEST port numbers picked randomly over the given range + * @return an available/free port + */ + public static synchronized int getAvailablePort(int randomAttempts) { + ArrayList failedPorts = new ArrayList(randomAttempts); + + Random randomNum = new Random(); + int randomPort = MAX_PORT_NUMBER; + + while (randomAttempts > 0) { + randomPort = randomNum.nextInt(MAX_PORT_NUMBER - MIN_PORT_NUMBER) + MIN_PORT_NUMBER; + + if (checkIfPortAvailable(randomPort)) { + return randomPort; + } + failedPorts.add(randomPort); + randomAttempts--; + } + + randomPort = MAX_PORT_NUMBER; + + while (true) { + if (!failedPorts.contains(randomPort) && checkIfPortAvailable(randomPort)) { + return randomPort; + } + randomPort--; + } + } + + + private static boolean checkIfPortAvailable(int port) { + ServerSocket tcpSocket = null; + DatagramSocket udpSocket = null; + + try { + tcpSocket = new ServerSocket(port); + tcpSocket.setReuseAddress(true); + + udpSocket = new DatagramSocket(port); + udpSocket.setReuseAddress(true); + return true; + } catch (IOException ex) { + // denotes the port is in use + } finally { + if (tcpSocket != null) { + try { + tcpSocket.close(); + } catch (IOException e) { + /* not to be thrown */ + } + } + + if (udpSocket != null) { + udpSocket.close(); + } + } + + return false; + } + + + /** + * This is a utility method that creates and returns a HTTP connection object. + * + * @param urlString the URL pattern to which the connection needs to be created + * @return an HTTPConnection object which cn be used to send HTTP requests + * @throws TransportHandlerException if errors occur when creating the HTTP connection with + * the given URL string + */ + public static HttpURLConnection getHttpConnection(String urlString) throws + TransportHandlerException { + URL connectionUrl; + HttpURLConnection httpConnection; + + try { + connectionUrl = new URL(urlString); + httpConnection = (HttpURLConnection) connectionUrl.openConnection(); + } catch (MalformedURLException e) { + String errorMsg = "Error occured whilst trying to form HTTP-URL from string: " + urlString; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } catch (IOException exception) { + String errorMsg = "Error occured whilst trying to open a connection to: " + urlString; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + return httpConnection; + } + + /** + * This is a utility method that reads and returns the response from a HTTP connection + * + * @param httpConnection the connection from which a response is expected + * @return the response (as a string) from the given HTTP connection + * @throws TransportHandlerException if any errors occur whilst reading the response from + * the connection stream + */ + public static String readResponseFromHttpRequest(HttpURLConnection httpConnection) + throws TransportHandlerException { + BufferedReader bufferedReader; + try { + bufferedReader = new BufferedReader(new InputStreamReader( + httpConnection.getInputStream(), StandardCharsets.UTF_8)); + } catch (IOException exception) { + String errorMsg = "There is an issue with connecting the reader to the input stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + + String responseLine; + StringBuilder completeResponse = new StringBuilder(); + + try { + while ((responseLine = bufferedReader.readLine()) != null) { + completeResponse.append(responseLine); + } + } catch (IOException exception) { + String errorMsg = "Error occured whilst trying read from the connection stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, exception); + } + try { + bufferedReader.close(); + } catch (IOException exception) { + log.error("Could not succesfully close the bufferedReader to the connection at: " + httpConnection.getURL()); + } + return completeResponse.toString(); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java new file mode 100644 index 000000000..c771eb8ed --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/http/HTTPTransportHandler.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.http; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.server.Server; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportUtils; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + */ +public abstract class HTTPTransportHandler implements TransportHandler { + private static final Log log = LogFactory.getLog(HTTPTransportHandler.class); + + protected Server server; + protected int port; + protected int timeoutInterval; + + protected HTTPTransportHandler() { + this.port = TransportUtils.getAvailablePort(10); + this.server = new Server(port); + timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + } + + protected HTTPTransportHandler(int port) { + this.port = port; + this.server = new Server(this.port); + timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + } + + protected HTTPTransportHandler(int port, int timeoutInterval) { + this.port = port; + this.server = new Server(this.port); + this.timeoutInterval = timeoutInterval; + } + + public void setTimeoutInterval(int timeoutInterval) { + this.timeoutInterval = timeoutInterval; + } + + /** + * Checks whether the HTTP server is up and listening for incoming requests. + * + * @return true if the server is up & listening for requests, else false. + */ + public boolean isConnected() { + return server.isStarted(); + } + + + protected void incrementPort() { + this.port = this.port + 1; + server = new Server(port); + } + + /** + * Shuts-down the HTTP Server. + */ + public void closeConnection() throws Exception { + if (server != null && isConnected()) { + server.stop(); + } + } + + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java new file mode 100644 index 000000000..597f50a4d --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/mqtt/MQTTTransportHandler.java @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.mqtt; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + *

      + * This class contains the Device-Management specific implementation for all the MQTT functionality. This includes + * connecting to a MQTT Broker & subscribing to the appropriate MQTT-topic, action plan upon losing connection or + * successfully delivering a message to the broker and processing incoming messages. Makes use of the 'Paho-MQTT' + * library provided by Eclipse Org. + */ +public abstract class MQTTTransportHandler + implements MqttCallback, TransportHandler { + private static final Log log = LogFactory.getLog(MQTTTransportHandler.class); + + public static final int DEFAULT_MQTT_QUALITY_OF_SERVICE = 0; + + private MqttClient client; + private String clientId; + private MqttConnectOptions options; + private String clientWillTopic; + + protected String mqttBrokerEndPoint; + protected int timeoutInterval; + protected String subscribeTopic; + + /** + * Constructor for the MQTTTransportHandler which takes in the owner, type of the device + * and the MQTT Broker URL and the topic to subscribe. + * + * @param deviceOwner the owner of the device. + * @param deviceType the CDMF Device-Type of the device. + * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint. + * @param subscribeTopic the MQTT topic to which the client is to be subscribed + */ + protected MQTTTransportHandler(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, + String subscribeTopic) { + this.clientId = deviceOwner + ":" + deviceType; + this.subscribeTopic = subscribeTopic; + this.clientWillTopic = deviceType + File.separator + "disconnection"; + this.mqttBrokerEndPoint = mqttBrokerEndPoint; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + this.initSubscriber(); + } + + /** + * Constructor for the MQTTTransportHandler which takes in the owner, type of the device + * and the MQTT Broker URL and the topic to subscribe. Additionally this constructor takes in + * the reconnection-time interval between successive attempts to connect to the broker. + * + * @param deviceOwner the owner of the device. + * @param deviceType the CDMF Device-Type of the device. + * @param mqttBrokerEndPoint the IP/URL of the MQTT broker endpoint. + * @param subscribeTopic the MQTT topic to which the client is to be subscribed + * @param intervalInMillis the time interval in MILLI-SECONDS between successive + * attempts to connect to the broker. + */ + protected MQTTTransportHandler(String deviceOwner, String deviceType, + String mqttBrokerEndPoint, String subscribeTopic, + int intervalInMillis) { + this.clientId = deviceOwner + ":" + deviceType; + this.subscribeTopic = subscribeTopic; + //TODO:: Use constant strings + this.clientWillTopic = deviceType + File.separator + "disconnection"; + this.mqttBrokerEndPoint = mqttBrokerEndPoint; + this.timeoutInterval = intervalInMillis; + this.initSubscriber(); + } + + public void setTimeoutInterval(int timeoutInterval) { + this.timeoutInterval = timeoutInterval; + } + + /** + * Initializes the MQTT-Client. Creates a client using the given MQTT-broker endpoint and the + * clientId (which is constructed by a concatenation of [deviceOwner]:[deviceType]). Also sets + * the client's options parameter with the clientWillTopic (in-case of connection failure) and + * other info. Also sets the call-back this current class. + */ + private void initSubscriber() { + try { + client = new MqttClient(this.mqttBrokerEndPoint, clientId, null); + //TODO:: Need to check for debug + log.info("MQTT subscriber was created with ClientID : " + clientId); + } catch (MqttException ex) { + //TODO:: Remove unnecessary formatting and print exception + String errorMsg = "MQTT Client Error\n" + "\tReason: " + ex.getReasonCode() + + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + + "\n\tException: " + ex; + log.error(errorMsg); + //TODO:: Throw the error out + } + + options = new MqttConnectOptions(); + options.setCleanSession(false); + //TODO:: Use constant strings + options.setWill(clientWillTopic, "Connection-Lost".getBytes(StandardCharsets.UTF_8), 2, + true); + client.setCallback(this); + } + + /** + * Checks whether the connection to the MQTT-Broker persists. + * + * @return true if the client is connected to the MQTT-Broker, else false. + */ + @Override + public boolean isConnected() { + return client.isConnected(); + } + + + /** + * Connects to the MQTT-Broker and if successfully established connection. + * + * @throws TransportHandlerException in the event of 'Connecting to' the MQTT broker fails. + */ + protected void connectToQueue() throws TransportHandlerException { + try { + client.connect(options); + + if (log.isDebugEnabled()) { + log.debug("Subscriber connected to queue at: " + this.mqttBrokerEndPoint); + } + } catch (MqttSecurityException ex) { + String errorMsg = "MQTT Security Exception when connecting to queue\n" + "\tReason: " + + " " + + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + + ex.getCause() + "\n\tException: " + ex; + //TODO:: Compulsory log of errors and remove formatted error + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + throw new TransportHandlerException(errorMsg, ex); + + } catch (MqttException ex) { + //TODO:: Compulsory log of errors and remove formatted error + String errorMsg = "MQTT Exception when connecting to queue\n" + "\tReason: " + + ex.getReasonCode() + "\n\tMessage: " + ex.getMessage() + + "\n\tLocalMsg: " + ex.getLocalizedMessage() + "\n\tCause: " + + ex.getCause() + "\n\tException: " + ex; + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + throw new TransportHandlerException(errorMsg, ex); + } + } + + /** + * Subscribes to the MQTT-Topic specific to this MQTT Client. (The MQTT-Topic specific to the + * device is taken in as a constructor parameter of this class) . + * + * @throws TransportHandlerException in the event of 'Subscribing to' the MQTT broker + * fails. + */ + protected void subscribeToQueue() throws TransportHandlerException { + try { + //TODO:: QoS Level take it from a variable + client.subscribe(subscribeTopic, 0); + log.info("Subscriber '" + clientId + "' subscribed to topic: " + subscribeTopic); + } catch (MqttException ex) { + //TODO:: Compulsory log of errors and remove formatted error + String errorMsg = "MQTT Exception when trying to subscribe to topic: " + + subscribeTopic + "\n\tReason: " + ex.getReasonCode() + + "\n\tMessage: " + ex.getMessage() + "\n\tLocalMsg: " + + ex.getLocalizedMessage() + "\n\tCause: " + ex.getCause() + + "\n\tException: " + ex; + if (log.isDebugEnabled()) { + log.debug(errorMsg); + } + + throw new TransportHandlerException(errorMsg, ex); + } + } + + + /** + * This method is used to publish reply-messages for the control signals received. + * Invocation of this method calls its overloaded-method with a QoS equal to that of the + * default value. + * + * @param topic the topic to which the reply message is to be published. + * @param payLoad the reply-message (payload) of the MQTT publish action. + */ + protected void publishToQueue(String topic, String payLoad) + throws TransportHandlerException { + publishToQueue(topic, payLoad, DEFAULT_MQTT_QUALITY_OF_SERVICE, false); + } + + /** + * This is an overloaded method that publishes MQTT reply-messages for control signals + * received form the IoT-Server. + * + * @param topic the topic to which the reply message is to be published + * @param payLoad the reply-message (payload) of the MQTT publish action. + * @param qos the Quality-of-Service of the current publish action. + * Could be 0(At-most once), 1(At-least once) or 2(Exactly once) + */ + protected void publishToQueue(String topic, String payLoad, int qos, boolean retained) + throws TransportHandlerException { + try { + client.publish(topic, payLoad.getBytes(StandardCharsets.UTF_8), qos, retained); + if (log.isDebugEnabled()) { + log.debug("Message: " + payLoad + " to MQTT topic [" + topic + + "] published successfully"); + } + } catch (MqttException ex) { + String errorMsg = + "MQTT Client Error" + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " + + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + + protected void publishToQueue(String topic, MqttMessage message) + throws TransportHandlerException { + try { + client.publish(topic, message); + if (log.isDebugEnabled()) { + log.debug("Message: " + message.toString() + " to MQTT topic [" + topic + + "] published successfully"); + } + } catch (MqttException ex) { + //TODO:: Compulsory log of errors and remove formatted error + String errorMsg = + "MQTT Client Error" + "\n\tReason: " + ex.getReasonCode() + "\n\tMessage: " + + ex.getMessage() + "\n\tLocalMsg: " + ex.getLocalizedMessage() + + "\n\tCause: " + ex.getCause() + "\n\tException: " + ex; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, ex); + } + } + + + /** + * Callback method which is triggered once the MQTT client losers its connection to the broker. + * Spawns a new thread that executes necessary actions to try and reconnect to the endpoint. + * + * @param throwable a Throwable Object containing the details as to why the failure occurred. + */ + @Override + public void connectionLost(Throwable throwable) { + log.warn("Lost Connection for client: " + this.clientId + + " to " + this.mqttBrokerEndPoint + ".\nThis was due to - " + + throwable.getMessage()); + + Thread reconnectThread = new Thread() { + public void run() { + connect(); + } + }; + reconnectThread.setDaemon(true); + reconnectThread.start(); + } + + /** + * Callback method which is triggered upon receiving a MQTT Message from the broker. Spawns a + * new thread that executes any actions to be taken with the received message. + * + * @param topic the MQTT-Topic to which the received message was published to and the + * client was subscribed to. + * @param mqttMessage the actual MQTT-Message that was received from the broker. + */ + @Override + public void messageArrived(final String topic, final MqttMessage mqttMessage) { + if (log.isDebugEnabled()) { + log.info("Got an MQTT message '" + mqttMessage.toString() + "' for topic '" + topic + "'."); + } + + Thread messageProcessorThread = new Thread() { + public void run() { + processIncomingMessage(mqttMessage, topic); + } + }; + messageProcessorThread.setDaemon(true); + messageProcessorThread.start(); + } + + /** + * Callback method which gets triggered upon successful completion of a message delivery to + * the broker. + * + * @param iMqttDeliveryToken the MQTT-DeliveryToken which includes the details about the + * specific message delivery. + */ + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + String message = ""; + try { + message = iMqttDeliveryToken.getMessage().toString(); + } catch (MqttException e) { + //TODO:: Throw errors + log.error( + "Error occurred whilst trying to read the message from the MQTT delivery " + + "token."); + } + String topic = iMqttDeliveryToken.getTopics()[0]; + String client = iMqttDeliveryToken.getClient().getClientId(); + + if (log.isDebugEnabled()) { + log.debug("Message - '" + message + "' of client [" + client + "] for the topic (" + + topic + ") was delivered successfully."); + } + } + + /** + * Closes the connection to the MQTT Broker. + */ + public void closeConnection() throws MqttException { + if (client != null && isConnected()) { + client.disconnect(); + } + } +} + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java new file mode 100644 index 000000000..4ac76f45b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/transport/xmpp/XMPPTransportHandler.java @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.xmpp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.ConnectionConfiguration; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.AndFilter; +import org.jivesoftware.smack.filter.FromContainsFilter; +import org.jivesoftware.smack.filter.OrFilter; +import org.jivesoftware.smack.filter.PacketFilter; +import org.jivesoftware.smack.filter.PacketTypeFilter; +import org.jivesoftware.smack.filter.ToContainsFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.transport.TransportHandlerException; + +/** + * This is an abstract class that implements the "TransportHandler" interface. The interface is an abstraction for + * the core functionality with regards to device-server communication regardless of the Transport protocol. This + * specific class contains the HTTP-Transport specific implementations. The class implements utility methods for the + * case of a HTTP communication. However, this "abstract class", even-though it implements the "TransportHandler" + * interface, does not contain the logic relevant to the interface methods. The specific functionality of the + * interface methods are intended to be implemented by the concrete class that extends this abstract class and + * utilizes the HTTP specific functionality (ideally a device API writer who would like to communicate to the device + * via HTTP Protocol). + *

      + * This class contains the IoT-Server specific implementation for all the XMPP functionality. This includes + * connecting to a XMPP Server & Login-In using the device's/server's XMPP-Account, Setting listeners and filters on + * incoming XMPP messages and Sending XMPP replies for messages received. Makes use of the 'Smack-XMPP' library + * provided by jivesoftware/igniterealtime. + */ +public abstract class XMPPTransportHandler implements TransportHandler { + private static final Log log = LogFactory.getLog(XMPPTransportHandler.class); + + protected String server; + protected int timeoutInterval; // millis + + //TODO:: Shouldnt be hard-coded. Need to be read from configs + private static final int DEFAULT_XMPP_PORT = 5222; + private XMPPConnection connection; + private int port; + private ConnectionConfiguration config; + private PacketFilter filter; + private PacketListener listener; + + + /** + * Constructor for XMPPTransportHandler passing only the server-IP. + * + * @param server the IP of the XMPP server. + */ + protected XMPPTransportHandler(String server) { + this.server = server; + this.port = DEFAULT_XMPP_PORT; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + initXMPPClient(); + } + + /** + * Constructor for XMPPTransportHandler passing server-IP and the XMPP-port. + * + * @param server the IP of the XMPP server. + * @param port the XMPP server's port to connect to. (default - 5222) + */ + protected XMPPTransportHandler(String server, int port) { + this.server = server; + this.port = port; + this.timeoutInterval = DEFAULT_TIMEOUT_INTERVAL; + initXMPPClient(); + } + + /** + * Constructor for XMPPTransportHandler passing server-IP, the XMPP-port and the + * timeoutInterval used by listeners to the server and for reconnection schedules. + * + * @param server the IP of the XMPP server. + * @param port the XMPP server's port to connect to. (default - 5222) + * @param timeoutInterval the timeout interval to use for the connection and reconnection + */ + protected XMPPTransportHandler(String server, int port, int timeoutInterval) { + this.server = server; + this.port = port; + this.timeoutInterval = timeoutInterval; + initXMPPClient(); + } + + /** + * Sets the client's time-out-limit whilst waiting for XMPP-replies from server. + * + * @param millis the time in millis to be set as the time-out-limit whilst waiting for a + * XMPP-reply. + */ + public void setTimeoutInterval(int millis) { + this.timeoutInterval = millis; + } + + /** + * Checks whether the connection to the XMPP-Server persists. + * + * @return true if the client is connected to the XMPP-Server, else false. + */ + @Override + public boolean isConnected() { + return connection.isConnected(); + } + + /** + * Initializes the XMPP Client. Sets the time-out-limit whilst waiting for XMPP-replies from + * server. Sets the XMPP configurations to connect to the server and creates the + * XMPPConnection object used for connecting and Logging-In. + */ + private void initXMPPClient() { + log.info(String.format("Initializing connection to XMPP Server at %1$s via port " + + "%2$d.", server, port)); + SmackConfiguration.setPacketReplyTimeout(timeoutInterval); + config = new ConnectionConfiguration(server, port); +// TODO:: Need to enable SASL-Authentication appropriately + config.setSASLAuthenticationEnabled(false); + config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled); + connection = new XMPPConnection(config); + } + +//TODO:: Re-check all exception handling + + /** + * Connects to the XMPP-Server and if attempt unsuccessful, then throws exception. + * + * @throws TransportHandlerException in the event of 'Connecting to' the XMPP server fails. + */ + protected void connectToServer() throws TransportHandlerException { + try { + connection.connect(); + log.info(String.format("Connection to XMPP Server at %1$s established successfully......", server)); + + } catch (XMPPException xmppExcepion) { + String errorMsg = "Connection attempt to the XMPP Server at " + server + " via port " + port + " failed."; + log.info(errorMsg); + throw new TransportHandlerException(errorMsg, xmppExcepion); + } + } + + /** + * If successfully established connection, then tries to Log in using the device's XMPP + * Account credentials. + * + * @param username the username of the device's XMPP-Account. + * @param password the password of the device's XMPP-Account. + * @param resource the resource the resource, specific to the XMPP-Account to which the login + * is made to + * @throws TransportHandlerException in the event of 'Logging into' the XMPP server fails. + */ + protected void loginToServer(String username, String password, String resource) + throws TransportHandlerException { + if (isConnected()) { + try { + if (resource == null) { + connection.login(username, password); + log.info(String.format("Logged into XMPP Server at %1$s as user %2$s......", server, username)); + } else { + connection.login(username, password, resource); + log.info(String.format("Logged into XMPP Server at %1$s as user %2$s on resource %3$s......", + server, username, resource)); + } + } catch (XMPPException xmppException) { + String errorMsg = + "Login attempt to the XMPP Server at " + server + " with username - " + username + " failed."; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, xmppException); + } + } else { + String errorMsg = "Not connected to XMPP-Server to attempt Login. Please 'connectToServer' before Login"; + throw new TransportHandlerException(errorMsg); + } + } + + + /** + * Sets a filter for all the incoming XMPP-Messages on the Sender's JID (XMPP-Account ID). + * Also creates a listener for the incoming messages and connects the listener to the + * XMPPConnection alongside the set filter. + * + * @param senderJID the JID (XMPP-Account ID of the sender) to which the filter is to be set. + */ + protected void setFilterOnSender(String senderJID) { + filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter( + senderJID)); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + processIncomingMessage(xmppMessage); + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + + connection.addPacketListener(listener, filter); + } + + + /** + * Sets a filter for all the incoming XMPP-Messages on the Receiver's JID (XMPP-Account ID). + * Also creates a listener for the incoming messages and connects the listener to the + * XMPPConnection alongside the set filter. + * + * @param receiverJID the JID (XMPP-Account ID of the receiver) to which the filter is to be + * set. + */ + protected void setFilterOnReceiver(String receiverJID) { + filter = new AndFilter(new PacketTypeFilter(Message.class), new ToContainsFilter( + receiverJID)); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + processIncomingMessage(xmppMessage); + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + + connection.addPacketListener(listener, filter); + } + + + /** + * Sets a filter for all the incoming XMPP-Messages on the From-JID & To-JID (XMPP-Account IDs) + * passed in. Also creates a listener for the incoming messages and connects the listener to + * the XMPPConnection alongside the set filter. + * + * @param senderJID the From-JID (XMPP-Account ID) to which the filter is to be set. + * @param receiverJID the To-JID (XMPP-Account ID) to which the filter is to be set. + * @param andCondition if true: then filter is set with 'AND' operator (senderJID && + * receiverJID), + * if false: then the filter is set with 'OR' operator (senderJID | + * receiverJID) + */ + protected void setMessageFilterAndListener(String senderJID, String receiverJID, boolean + andCondition) { + PacketFilter jidFilter; + + if (andCondition) { + jidFilter = new AndFilter(new FromContainsFilter(senderJID), new ToContainsFilter( + receiverJID)); + } else { + jidFilter = new OrFilter(new FromContainsFilter(senderJID), new ToContainsFilter( + receiverJID)); + } + + filter = new AndFilter(new PacketTypeFilter(Message.class), jidFilter); + listener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + if (packet instanceof Message) { + final Message xmppMessage = (Message) packet; + Thread msgProcessThread = new Thread() { + public void run() { + processIncomingMessage(xmppMessage); + } + }; + msgProcessThread.setDaemon(true); + msgProcessThread.start(); + } + } + }; + + connection.addPacketListener(listener, filter); + } + + + /** + * Sends an XMPP message. Calls the overloaded method with Subject set to "Reply-From-Device" + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param message the XMPP-Message that is to be sent. + */ + protected void sendXMPPMessage(String JID, String message) { + sendXMPPMessage(JID, message, "XMPP-Message"); + } + + + /** + * Overloaded method to send an XMPP message. Includes the subject to be mentioned in the + * message that is sent. + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param message the XMPP-Message that is to be sent. + * @param subject the subject that the XMPP-Message would carry. + */ + protected void sendXMPPMessage(String JID, String message, String subject) { + Message xmppMessage = new Message(); + xmppMessage.setTo(JID); + xmppMessage.setSubject(subject); + xmppMessage.setBody(message); + xmppMessage.setType(Message.Type.chat); + sendXMPPMessage(JID, xmppMessage); + } + + + /** + * Sends an XMPP message. + * + * @param JID the JID (XMPP Account ID) to which the message is to be sent to. + * @param xmppMessage the XMPP-Message that is to be sent. + */ + protected void sendXMPPMessage(String JID, Message xmppMessage) { + connection.sendPacket(xmppMessage); + if (log.isDebugEnabled()) { + log.debug("Message: '" + xmppMessage.getBody() + "' sent to XMPP JID [" + JID + + "] sent successfully."); + } + } + + + /** + * Disables default debugger provided by the XMPPConnection. + */ + protected void disableDebugger() { + connection.DEBUG_ENABLED = false; + } + + + /** + * Closes the connection to the XMPP Server. + */ + public void closeConnection() { + if (connection != null && isConnected()) { + connection.disconnect(); + } + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java new file mode 100644 index 000000000..3b777cf75 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/VirtualHardwareManager.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentUtilOperations; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.ui.AgentUI; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.sampled.Clip; +import javax.swing.*; +import java.io.IOException; +import java.io.InputStream; + +/** + * This class use to emulate virtual hardware functionality + */ +public class VirtualHardwareManager { + + private static final Log log = LogFactory.getLog(VirtualHardwareManager.class); + + private static VirtualHardwareManager virtualHardwareManager; + + private AgentUI agentUI; + private Sequencer sequencer = null; + + private int temperature = 30, humidity = 30; + private int temperatureMin = 20, temperatureMax = 50, humidityMin = 20, humidityMax = 50; + private int temperatureSVF = 50, humiditySVF = 50; + private boolean isTemperatureRandomized, isHumidityRandomized; + private boolean isTemperatureSmoothed, isHumiditySmoothed; + + private VirtualHardwareManager(){ + } + + public static VirtualHardwareManager getInstance(){ + if (virtualHardwareManager == null){ + virtualHardwareManager = new VirtualHardwareManager(); + } + return virtualHardwareManager; + } + + public void init(){ + try { + // Set System L&F for Device UI + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (UnsupportedLookAndFeelException e) { + log.error( + "'UnsupportedLookAndFeelException' error occurred whilst initializing the" + + " Agent UI."); + } catch (ClassNotFoundException e) { + log.error( + "'ClassNotFoundException' error occurred whilst initializing the Agent UI."); + } catch (InstantiationException e) { + log.error( + "'InstantiationException' error occurred whilst initializing the Agent UI."); + } catch (IllegalAccessException e) { + log.error( + "'IllegalAccessException' error occurred whilst initializing the Agent UI."); + } + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + agentUI = new AgentUI(); + agentUI.setVisible(true); + } + }); + setAudioSequencer(); + } + + /** + * Get temperature from emulated device + * @return Temperature + */ + public int getTemperature() { + if (isTemperatureRandomized) { + temperature = getRandom(temperatureMax, temperatureMin, temperature, + isTemperatureSmoothed, temperatureSVF); + agentUI.updateTemperature(temperature); + } + return temperature; + } + + public void setTemperature(int temperature) { + this.temperature = temperature; + } + + /** + * Get humidity from emulated device + * @return Humidity + */ + public int getHumidity() { + if (isHumidityRandomized) { + humidity = getRandom(humidityMax, humidityMin, humidity, isHumiditySmoothed, + humiditySVF); + agentUI.updateHumidity(humidity); + } + return humidity; + } + + public void setHumidity(int humidity) { + this.humidity = humidity; + } + + public void setTemperatureMin(int temperatureMin) { + this.temperatureMin = temperatureMin; + } + + public void setTemperatureMax(int temperatureMax) { + this.temperatureMax = temperatureMax; + } + + public void setHumidityMin(int humidityMin) { + this.humidityMin = humidityMin; + } + + public void setHumidityMax(int humidityMax) { + this.humidityMax = humidityMax; + } + + public void setIsHumidityRandomized(boolean isHumidityRandomized) { + this.isHumidityRandomized = isHumidityRandomized; + } + + public void setIsTemperatureRandomized(boolean isTemperatureRandomized) { + this.isTemperatureRandomized = isTemperatureRandomized; + } + + public void setTemperatureSVF(int temperatureSVF) { + this.temperatureSVF = temperatureSVF; + } + + public void setHumiditySVF(int humiditySVF) { + this.humiditySVF = humiditySVF; + } + + public void setIsTemperatureSmoothed(boolean isTemperatureSmoothed) { + this.isTemperatureSmoothed = isTemperatureSmoothed; + } + + public void setIsHumiditySmoothed(boolean isHumiditySmoothed) { + this.isHumiditySmoothed = isHumiditySmoothed; + } + + public void changeAlarmStatus(boolean isOn) { + agentUI.setAlarmStatus(isOn); + + if (isOn) { + sequencer.start(); + } else { + sequencer.stop(); + } + } + + private int getRandom(int max, int min, int current, boolean isSmoothed, int svf) { + + if (isSmoothed) { + int offset = (max - min) * svf / 100; + double mx = current + offset; + max = (mx > max) ? max : (int) Math.round(mx); + + double mn = current - offset; + min = (mn < min) ? min : (int) Math.round(mn); + } + + double rnd = Math.random() * (max - min) + min; + return (int) Math.round(rnd); + + } + + private void setAudioSequencer() { + InputStream audioSrc = AgentUtilOperations.class.getResourceAsStream( + "/" + AgentConstants.AUDIO_FILE_NAME); + Sequence sequence; + + try { + sequence = MidiSystem.getSequence(audioSrc); + sequencer = MidiSystem.getSequencer(); + sequencer.open(); + sequencer.setSequence(sequence); + } catch (InvalidMidiDataException e) { + log.error("AudioReader: Error whilst setting MIDI Audio reader sequence"); + } catch (IOException e) { + log.error("AudioReader: Error whilst getting audio sequence from stream"); + } catch (MidiUnavailableException e) { + log.error("AudioReader: Error whilst openning MIDI Audio reader sequencer"); + } + + sequencer.setLoopCount(Clip.LOOP_CONTINUOUSLY); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java new file mode 100644 index 000000000..4a9b76c86 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/agent/virtual/ui/AgentUI.java @@ -0,0 +1,954 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.ui; + +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.core.AgentManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.virtual.VirtualHardwareManager; + +import javax.swing.*; +import java.awt.*; +import java.net.URI; +import java.net.URL; + +public class AgentUI extends JFrame { + + private boolean isTemperatureRandomized, isHumidityRandomized; + private boolean isTemperatureSmoothed, isHumiditySmoothed; + + private volatile boolean isAlarmOn = false; + + private JLabel picLabelBulbOn, picLabelBulbOff; + + // Variables declaration - do not modify + private JButton btnControl; + private JButton btnView; + private JCheckBox chkbxEmulate; + private JCheckBox chkbxHumidityRandom; + private JCheckBox chkbxHumiditySmooth; + private JCheckBox chkbxTemperatureRandom; + private JCheckBox chkbxTemperatureSmooth; + private JComboBox cmbInterface; + private JComboBox cmbPeriod; + private JComboBox cmbProtocol; + private JLabel jLabel1; + private JLabel jLabel10; + private JLabel jLabel11; + private JLabel jLabel12; + private JLabel jLabel2; + private JLabel jLabel20; + private JLabel jLabel23; + private JLabel jLabel24; + private JLabel jLabel25; + private JLabel jLabel3; + private JLabel jLabel4; + private JLabel jLabel5; + private JLabel jLabel6; + private JLabel jLabel7; + private JLabel jLabel8; + private JLabel jLabel9; + private JPanel jPanel1; + private JPanel jPanel2; + private JPanel jPanel3; + private JPanel jPanel4; + private JPanel jPanel6; + private JPanel jPanel7; + private JPanel jPanel8; + private JPanel jPanel9; + private JSeparator jSeparator1; + private JSeparator jSeparator5; + private JLabel lblAgentName; + private JLabel lblStatus; + private JPanel pnlBulbStatus; + private JSpinner spinnerHumidity; + private JSpinner spinnerInterval; + private JSpinner spinnerTemperature; + private JTextField txtHumidityMax; + private JTextField txtHumidityMin; + private JTextField txtHumiditySVF; + private JTextField txtTemperatureMax; + private JTextField txtTemperatureMin; + private JTextField txtTemperatureSVF; + // End of variables declaration + + private Runnable uiUpdater = new Runnable() { + @Override + public void run() { + while (true) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + pnlBulbStatus.removeAll(); + pnlBulbStatus.add(isAlarmOn ? picLabelBulbOn : picLabelBulbOff); + pnlBulbStatus.updateUI(); + lblStatus.setText(AgentManager.getInstance().getAgentStatus()); + if (isTemperatureRandomized) { + txtTemperatureMinActionPerformed(null); + txtTemperatureMaxActionPerformed(null); + if (isTemperatureSmoothed) { + txtTemperatureSVFActionPerformed(null); + } + } + if (isHumidityRandomized) { + txtHumidityMinActionPerformed(null); + txtHumidityMaxActionPerformed(null); + if (isHumiditySmoothed) { + txtHumiditySVFActionPerformed(null); + } + } + } + }); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + } + } + }; + + /** + * Creates new form AgentUI + */ + public AgentUI() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + private void initComponents() { + + lblAgentName = new JLabel(); + jLabel2 = new JLabel(); + jPanel1 = new JPanel(); + jLabel3 = new JLabel(); + pnlBulbStatus = new JPanel(); + jPanel2 = new JPanel(); + jLabel4 = new JLabel(); + chkbxTemperatureRandom = new JCheckBox(); + jSeparator1 = new JSeparator(); + jPanel7 = new JPanel(); + jLabel5 = new JLabel(); + txtTemperatureMin = new JTextField(); + jLabel6 = new JLabel(); + txtTemperatureMax = new JTextField(); + jLabel10 = new JLabel(); + txtTemperatureSVF = new JTextField(); + spinnerTemperature = new JSpinner(); + chkbxTemperatureSmooth = new JCheckBox(); + jPanel6 = new JPanel(); + jLabel20 = new JLabel(); + btnView = new JButton(); + btnControl = new JButton(); + lblStatus = new JLabel(); + jPanel8 = new JPanel(); + jLabel23 = new JLabel(); + chkbxHumidityRandom = new JCheckBox(); + jSeparator5 = new JSeparator(); + jPanel9 = new JPanel(); + jLabel24 = new JLabel(); + txtHumidityMin = new JTextField(); + jLabel25 = new JLabel(); + txtHumidityMax = new JTextField(); + txtHumiditySVF = new JTextField(); + jLabel11 = new JLabel(); + spinnerHumidity = new JSpinner(); + chkbxHumiditySmooth = new JCheckBox(); + jPanel3 = new JPanel(); + jLabel7 = new JLabel(); + spinnerInterval = new JSpinner(); + jLabel8 = new JLabel(); + jLabel9 = new JLabel(); + cmbProtocol = new JComboBox(); + jLabel12 = new JLabel(); + cmbInterface = new JComboBox(); + jPanel4 = new JPanel(); + chkbxEmulate = new JCheckBox(); + cmbPeriod = new JComboBox(); + jLabel1 = new JLabel(); + + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + setTitle("Fire Alarm Emulator"); + setResizable(false); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation(dim.width / 2 - 650 / 2, dim.height / 2 - 440 / 2); + + lblAgentName.setFont(new Font("Cantarell", 1, 24)); // NOI18N + lblAgentName.setHorizontalAlignment(SwingConstants.LEFT); + lblAgentName.setText("Device Name: " + AgentManager.getInstance().getDeviceName()); + + jLabel2.setHorizontalAlignment(SwingConstants.CENTER); + jLabel2.setText("Copyright (c) 2015, WSO2 Inc."); + + jPanel1.setBackground(new Color(220, 220, 220)); + + jLabel3.setFont(new Font("Cantarell", 0, 18)); // NOI18N + jLabel3.setHorizontalAlignment(SwingConstants.CENTER); + jLabel3.setText("Alarm Status"); + + pnlBulbStatus.setBackground(new Color(220, 220, 220)); + + GroupLayout pnlBulbStatusLayout = new GroupLayout(pnlBulbStatus); + pnlBulbStatus.setLayout(pnlBulbStatusLayout); + pnlBulbStatusLayout.setHorizontalGroup( + pnlBulbStatusLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) + ); + pnlBulbStatusLayout.setVerticalGroup( + pnlBulbStatusLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGap(0, 167, Short.MAX_VALUE) + ); + + GroupLayout jPanel1Layout = new GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(GroupLayout.Alignment.TRAILING) + .addComponent(pnlBulbStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel3, GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel3) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlBulbStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + + jPanel2.setBackground(new Color(220, 220, 220)); + + jLabel4.setFont(new Font("Cantarell", 0, 18)); // NOI18N + jLabel4.setHorizontalAlignment(SwingConstants.CENTER); + jLabel4.setText("Temperature"); + + chkbxTemperatureRandom.setText("Randomize Data"); + chkbxTemperatureRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureRandomActionPerformed(evt); + } + }); + + jSeparator1.setOrientation(SwingConstants.VERTICAL); + + jPanel7.setBackground(new Color(220, 220, 220)); + + jLabel5.setHorizontalAlignment(SwingConstants.LEFT); + jLabel5.setText("Min"); + + txtTemperatureMin.setHorizontalAlignment(JTextField.CENTER); + txtTemperatureMin.setText("20"); + txtTemperatureMin.setEnabled(false); + txtTemperatureMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMinActionPerformed(evt); + } + }); + + jLabel6.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel6.setText("Max"); + + txtTemperatureMax.setHorizontalAlignment(JTextField.CENTER); + txtTemperatureMax.setText("50"); + txtTemperatureMax.setEnabled(false); + txtTemperatureMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMaxActionPerformed(evt); + } + }); + + jLabel10.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel10.setText("SV %"); + + txtTemperatureSVF.setHorizontalAlignment(JTextField.CENTER); + txtTemperatureSVF.setText("50"); + txtTemperatureSVF.setEnabled(false); + txtTemperatureSVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureSVFActionPerformed(evt); + } + }); + + GroupLayout jPanel7Layout = new GroupLayout(jPanel7); + jPanel7.setLayout(jPanel7Layout); + jPanel7Layout.setHorizontalGroup( + jPanel7Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel7Layout.createSequentialGroup() + .addComponent(jLabel5) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMin, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel6) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMax, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel10) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureSVF, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel7Layout.setVerticalGroup( + jPanel7Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel7Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(txtTemperatureMin, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(txtTemperatureMax, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6) + .addComponent(jLabel5) + .addComponent(jLabel10) + .addComponent(txtTemperatureSVF, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addGap(35, 35, 35)) + ); + + spinnerTemperature.setFont(new Font("Cantarell", 1, 24)); // NOI18N + spinnerTemperature.setModel(new SpinnerNumberModel(30, 0, 100, 1)); + spinnerTemperature.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerTemperatureStateChanged(evt); + } + }); + + chkbxTemperatureSmooth.setText("Smooth Variation"); + chkbxTemperatureSmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureSmoothActionPerformed(evt); + } + }); + + GroupLayout jPanel2Layout = new GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spinnerTemperature)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 6, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jPanel7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(chkbxTemperatureRandom) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxTemperatureSmooth))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jSeparator1) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup( + + GroupLayout.Alignment.BASELINE) + .addComponent(chkbxTemperatureRandom) + .addComponent(chkbxTemperatureSmooth)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel7, GroupLayout.PREFERRED_SIZE, 51, GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel4, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerTemperature))) + .addContainerGap()) + ); + + jPanel6.setBackground(new Color(253, 254, 209)); + + jLabel20.setText("Connection Status:"); + jLabel20.setVerticalTextPosition(SwingConstants.TOP); + + btnView.setText("View Device Data"); + btnView.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnViewMouseClicked(evt); + } + }); + + btnControl.setText("Control Device"); + btnControl.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnControlMouseClicked(evt); + } + }); + + lblStatus.setFont(new Font("Cantarell", 1, 15)); // NOI18N + lblStatus.setText("Not Connected"); + + GroupLayout jPanel6Layout = new GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel6Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel20) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnControl) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnView) + .addContainerGap()) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel20, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(btnView, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnControl) + .addComponent(lblStatus))) + .addContainerGap()) + ); + + jPanel8.setBackground(new Color(220, 220, 220)); + + jLabel23.setFont(new Font("Cantarell", 0, 18)); // NOI18N + jLabel23.setHorizontalAlignment(SwingConstants.CENTER); + jLabel23.setText("Humidity"); + + chkbxHumidityRandom.setText("Randomize Data"); + chkbxHumidityRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumidityRandomActionPerformed(evt); + } + }); + + jSeparator5.setOrientation(SwingConstants.VERTICAL); + + jPanel9.setBackground(new Color(220, 220, 220)); + + jLabel24.setHorizontalAlignment(SwingConstants.LEFT); + jLabel24.setText("Min"); + + txtHumidityMin.setHorizontalAlignment(JTextField.CENTER); + txtHumidityMin.setText("20"); + txtHumidityMin.setEnabled(false); + txtHumidityMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMinActionPerformed(evt); + } + }); + + jLabel25.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel25.setText("Max"); + + txtHumidityMax.setHorizontalAlignment(JTextField.CENTER); + txtHumidityMax.setText("50"); + txtHumidityMax.setEnabled(false); + txtHumidityMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMaxActionPerformed(evt); + } + }); + + txtHumiditySVF.setHorizontalAlignment(JTextField.CENTER); + txtHumiditySVF.setText("50"); + txtHumiditySVF.setEnabled(false); + txtHumiditySVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumiditySVFActionPerformed(evt); + } + }); + + jLabel11.setHorizontalAlignment(SwingConstants.RIGHT); + jLabel11.setText("SV %"); + + GroupLayout jPanel9Layout = new GroupLayout(jPanel9); + jPanel9.setLayout(jPanel9Layout); + jPanel9Layout.setHorizontalGroup( + jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createSequentialGroup() + .addComponent(jLabel24) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumidityMin, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel25) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumidityMax, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel11) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumiditySVF, GroupLayout.PREFERRED_SIZE, 45, GroupLayout.PREFERRED_SIZE) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel9Layout.setVerticalGroup( + jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel9Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel9Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(jLabel11) + .addComponent(txtHumiditySVF, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel9Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(txtHumidityMin, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(txtHumidityMax, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel25) + .addComponent(jLabel24))) + .addGap(35, 35, 35)) + ); + + spinnerHumidity.setFont(new Font("Cantarell", 1, 24)); // NOI18N + spinnerHumidity.setModel(new SpinnerNumberModel(30, 0, 100, 1)); + spinnerHumidity.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerHumidityStateChanged(evt); + } + }); + + chkbxHumiditySmooth.setText("Smooth Variation"); + chkbxHumiditySmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumiditySmoothActionPerformed(evt); + } + }); + + GroupLayout jPanel8Layout = new GroupLayout(jPanel8); + jPanel8.setLayout(jPanel8Layout); + jPanel8Layout.setHorizontalGroup( + jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jLabel23, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerHumidity)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator5, GroupLayout.PREFERRED_SIZE, 6, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(jPanel9, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(chkbxHumidityRandom) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxHumiditySmooth))) + .addContainerGap()) + ); + jPanel8Layout.setVerticalGroup( + jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(jSeparator5) + .addGroup(jPanel8Layout.createSequentialGroup() + .addGroup(jPanel8Layout.createParallelGroup( + GroupLayout.Alignment.BASELINE) + .addComponent(chkbxHumidityRandom) + .addComponent(chkbxHumiditySmooth)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel9, GroupLayout.PREFERRED_SIZE, 51, GroupLayout.PREFERRED_SIZE) + .addGap(0, 1, Short.MAX_VALUE)) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(jLabel23, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerHumidity))) + .addContainerGap()) + ); + + jPanel3.setBackground(new Color(207, 233, 234)); + + jLabel7.setText("Data Push Interval:"); + + spinnerInterval.setModel(new SpinnerNumberModel(Integer.valueOf(AgentManager.getInstance().getPushInterval()), Integer.valueOf(1), null, Integer.valueOf(1))); + spinnerInterval.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerIntervalStateChanged(evt); + } + }); + + jLabel8.setText("Seconds"); + + jLabel9.setText("Protocol:"); + + cmbProtocol.setModel(new DefaultComboBoxModel(new String[] { "MQTT", "XMPP", "HTTP" })); + cmbProtocol.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbProtocolActionPerformed(evt); + } + }); + + jLabel12.setText("Interface:"); + + cmbInterface.setModel(new DefaultComboBoxModel(new String[] { "eth0" })); + cmbInterface.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbInterfaceActionPerformed(evt); + } + }); + + GroupLayout jPanel3Layout = new GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel7) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerInterval, GroupLayout.PREFERRED_SIZE, 55, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel8) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel12) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbInterface, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel9) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbProtocol, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel3Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(jLabel12) + .addComponent(cmbInterface, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(jLabel7) + .addComponent(spinnerInterval, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel8) + .addComponent(jLabel9) + .addComponent(cmbProtocol, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + jPanel4.setBackground(new Color(169, 253, 173)); + + chkbxEmulate.setText("Emulate data"); + chkbxEmulate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxEmulateActionPerformed(evt); + } + }); + + cmbPeriod.setModel(new DefaultComboBoxModel(new String[] { "1 hour", "1 day", "1 week", "1 month " })); + cmbPeriod.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbPeriodActionPerformed(evt); + } + }); + + jLabel1.setText("Emulation Period"); + + GroupLayout jPanel4Layout = new GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addComponent(chkbxEmulate) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbPeriod, GroupLayout.PREFERRED_SIZE, 162, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel4Layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(chkbxEmulate) + .addComponent(cmbPeriod, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1)) + .addContainerGap()) + ); + + GroupLayout layout = new GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(lblAgentName, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel6, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup( + GroupLayout.Alignment.LEADING) + .addComponent(jPanel8, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(jLabel2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAgentName, GroupLayout.PREFERRED_SIZE, 53, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel8, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2, GroupLayout.PREFERRED_SIZE, 28, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + + chkbxTemperatureSmooth.setEnabled(false); + chkbxTemperatureSmooth.setEnabled(false); + + cmbInterface.removeAllItems(); + for (String item : AgentManager.getInstance().getInterfaceList()){ + cmbInterface.addItem(item); + } + cmbInterface.setEnabled(false); + + cmbProtocol.removeAllItems(); + for (String item : AgentManager.getInstance().getProtocolList()){ + cmbProtocol.addItem(item); + } + cmbProtocol.setSelectedItem(AgentConstants.DEFAULT_PROTOCOL); + + URL urlAlarmOn = this.getClass().getResource("/alarm-on.gif"); + ImageIcon imageIconAlarmOn = new ImageIcon(urlAlarmOn); + + URL urlAlarmOff = this.getClass().getResource("/alarm-off.gif"); + ImageIcon imageIconAlarmOff = new ImageIcon(urlAlarmOff); + + picLabelBulbOn = new JLabel(imageIconAlarmOn); + picLabelBulbOn.setSize(pnlBulbStatus.getSize()); + + picLabelBulbOff = new JLabel(imageIconAlarmOff); + picLabelBulbOff.setSize(pnlBulbStatus.getSize()); + + new Thread(uiUpdater).start(); + + AgentManager.getInstance().setDeviceReady(true); + } + + private void btnControlMouseClicked(java.awt.event.MouseEvent evt) { + Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + try { + URI uri = new URI(AgentManager.getInstance().getDeviceMgtControlUrl()); + desktop.browse(uri); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void btnViewMouseClicked(java.awt.event.MouseEvent evt) { + Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + try { + URI uri = new URI(AgentManager.getInstance().getDeviceMgtAnalyticUrl()); + desktop.browse(uri); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void chkbxTemperatureRandomActionPerformed(java.awt.event.ActionEvent evt) { + isTemperatureRandomized = chkbxTemperatureRandom.isSelected(); + VirtualHardwareManager.getInstance().setIsTemperatureRandomized(isTemperatureRandomized); + spinnerTemperature.setEnabled(!isTemperatureRandomized); + txtTemperatureMax.setEnabled(isTemperatureRandomized); + txtTemperatureMin.setEnabled(isTemperatureRandomized); + chkbxTemperatureSmooth.setEnabled(isTemperatureRandomized); + txtTemperatureSVF.setEnabled(isTemperatureRandomized && isTemperatureSmoothed); + } + + private void chkbxHumidityRandomActionPerformed(java.awt.event.ActionEvent evt) { + isHumidityRandomized = chkbxHumidityRandom.isSelected(); + VirtualHardwareManager.getInstance().setIsHumidityRandomized(isHumidityRandomized); + spinnerHumidity.setEnabled(!isHumidityRandomized); + txtHumidityMax.setEnabled(isHumidityRandomized); + txtHumidityMin.setEnabled(isHumidityRandomized); + chkbxHumiditySmooth.setEnabled(isHumidityRandomized); + txtTemperatureSVF.setEnabled(isHumidityRandomized && isHumiditySmoothed); + } + + private void spinnerTemperatureStateChanged(javax.swing.event.ChangeEvent evt) { + if (!isTemperatureRandomized) { + try { + int temperature = Integer.parseInt(spinnerTemperature.getValue().toString()); + VirtualHardwareManager.getInstance().setTemperature(temperature); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE); + spinnerTemperature.setValue(VirtualHardwareManager.getInstance().getTemperature()); + } + } + } + + private void spinnerHumidityStateChanged(javax.swing.event.ChangeEvent evt) { + if (!isHumidityRandomized) { + try { + int humidity = Integer.parseInt(spinnerHumidity.getValue().toString()); + VirtualHardwareManager.getInstance().setHumidity(humidity); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE); + spinnerHumidity.setValue(VirtualHardwareManager.getInstance().getHumidity()); + } + } + } + + private void txtTemperatureMinActionPerformed(java.awt.event.ActionEvent evt) { + try { + int temperature = Integer.parseInt(txtTemperatureMin.getText()); + VirtualHardwareManager.getInstance().setTemperatureMin(temperature); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE); + txtTemperatureMin.setText("20"); + } + } + + private void txtTemperatureMaxActionPerformed(java.awt.event.ActionEvent evt) { + try { + int temperature = Integer.parseInt(txtTemperatureMax.getText()); + VirtualHardwareManager.getInstance().setTemperatureMax(temperature); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid temperature value", "Error", JOptionPane.ERROR_MESSAGE); + txtTemperatureMax.setText("50"); + } + } + + private void txtHumidityMinActionPerformed(java.awt.event.ActionEvent evt) { + try { + int humidity = Integer.parseInt(txtHumidityMin.getText()); + VirtualHardwareManager.getInstance().setHumidityMin(humidity); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE); + txtHumidityMin.setText("20"); + } + } + + private void txtHumidityMaxActionPerformed(java.awt.event.ActionEvent evt) { + try { + int humidity = Integer.parseInt(txtHumidityMax.getText()); + VirtualHardwareManager.getInstance().setHumidityMax(humidity); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid humidity value", "Error", JOptionPane.ERROR_MESSAGE); + txtHumidityMax.setText("50"); + } + } + + private void spinnerIntervalStateChanged(javax.swing.event.ChangeEvent evt) { + try { + int interval = Integer.parseInt(spinnerInterval.getValue().toString()); + AgentManager.getInstance().setPushInterval(interval); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid time interval value", "Error", JOptionPane.ERROR_MESSAGE); + spinnerInterval.setValue(5); + } + } + + private void cmbInterfaceActionPerformed(java.awt.event.ActionEvent evt) { + AgentManager.getInstance().setInterface(cmbInterface.getSelectedIndex()); + } + + private void cmbProtocolActionPerformed(java.awt.event.ActionEvent evt) { + if (cmbProtocol.getSelectedIndex() != -1 && cmbProtocol.getItemAt( + cmbProtocol.getSelectedIndex()).equals(AgentConstants.HTTP_PROTOCOL)) { + cmbInterface.setEnabled(true); + } else { + cmbInterface.setEnabled(false); + } + + AgentManager.getInstance().setProtocol(cmbProtocol.getSelectedIndex()); + + } + + private void txtTemperatureSVFActionPerformed(java.awt.event.ActionEvent evt) { + try { + int temperatureSVF = Integer.parseInt(txtTemperatureSVF.getText()); + VirtualHardwareManager.getInstance().setTemperatureSVF(temperatureSVF); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid value", "Error", JOptionPane.ERROR_MESSAGE); + txtTemperatureSVF.setText("50"); + } + } + + private void txtHumiditySVFActionPerformed(java.awt.event.ActionEvent evt) { + try { + int humiditySVF = Integer.parseInt(txtHumiditySVF.getText()); + VirtualHardwareManager.getInstance().setHumiditySVF(humiditySVF); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Invalid value", "Error", JOptionPane.ERROR_MESSAGE); + txtHumiditySVF.setText("50"); + } + } + + private void chkbxTemperatureSmoothActionPerformed(java.awt.event.ActionEvent evt) { + isTemperatureSmoothed = chkbxTemperatureSmooth.isSelected(); + txtTemperatureSVF.setEnabled(isTemperatureSmoothed); + VirtualHardwareManager.getInstance().setIsTemperatureSmoothed(isTemperatureSmoothed); + } + + private void chkbxHumiditySmoothActionPerformed(java.awt.event.ActionEvent evt) { + isHumiditySmoothed = chkbxHumiditySmooth.isSelected(); + txtHumiditySVF.setEnabled(isHumiditySmoothed); + VirtualHardwareManager.getInstance().setIsHumiditySmoothed(isHumiditySmoothed); + } + + private void cmbPeriodActionPerformed(java.awt.event.ActionEvent evt) { + // TODO add your handling code here: + } + + private void chkbxEmulateActionPerformed(java.awt.event.ActionEvent evt) { + // TODO add your handling code here: + } + + public void setAlarmStatus(boolean isAlarmOn) { + this.isAlarmOn = isAlarmOn; + } + + public void updateTemperature(int temperature) { + spinnerTemperature.setValue(temperature); + spinnerTemperature.updateUI(); + } + + public void updateHumidity(int humidity) { + spinnerHumidity.setValue(humidity); + spinnerHumidity.updateUI(); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-off.gif b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/alarm-off.gif new file mode 100644 index 0000000000000000000000000000000000000000..c346605ad00627e4bda392cd37ab24bde7643395 GIT binary patch literal 4265 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 C_s;DA literal 0 HcmV?d00001 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties new file mode 100644 index 000000000..930742a2a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/deviceConfig.properties @@ -0,0 +1,33 @@ +# +# Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +# +# Licensed 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. +# +# + +#[Device-Configurations] +server-name=WSO2IoTServer +owner=shabirmean +deviceId=t4ctwq8qfl11 +device-name=SMEAN_t4ctwq8qfl11 +controller-context=/virtual_firealarm/controller +https-ep=https://localhost:9443 +http-ep=http://localhost:9763 +apim-ep=http://192.168.67.21:8281 +mqtt-ep=tcp://192.168.67.21:1883 +xmpp-ep=http://204.232.188.215:5222 +auth-method=token +auth-token=79d68b50ae5f5a06e812889979b3453 +refresh-token=8bdda6359dddad218cff3354d5a8cb3b +network-interface=en0 +push-interval=14 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/fireAlarmSound.mid b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/resources/fireAlarmSound.mid new file mode 100644 index 0000000000000000000000000000000000000000..d1a2241b2d87d668b9cfa999f05be6a8c477d895 GIT binary patch literal 6719 zcmeI%&rc&|7zglY+L=<>4Yh|&?8cA@YYBz~Q>>7XY15%lD8d3Q;20ul)6PO!VUezl zB_jA>{7SQ2H^mm&olGP zJ2TJw%nQsdZ6t}vMjSb~-{+QgFS9L)3btqF;=7mCUGc&NDl7>iQ=)>x^OooARCwK@ zZyniZ(aJrzM}?QDl;au|toEq-*4yfKLZt$Kc4|(XP&287Dtca_g2?sIL#L*l;W)d+ zZng7vo84jmhaR3M@uFtoI5r@T74j&7tuA3Ml+h^A(|nnUn9RJ^%MC?8rCSRNy9|p zqwdy-9l}CxB6d_wl!bhVvXHM)v{UEGKYv0mOzOaOv1ji`S+G)I72q!yM?-gK$&)2t zmcm)RCfpglEIb+g@%u8YJ}8`lr{QUM8lHylz<1y~@E!OTd<(t>--2(#H{qM`P53%| z9lj1TiJ4 zj(9>kV%4&Dy!ooa<(m1j>>~!u@{XW|v0Y0q%^(uMW@~Y*AfaKy!a%p(<8= zd21G`#eBKg#|dqJWIv&dl|INX{!Gp~EJrK5)l2?--C-@~s?XkXs_T1CZdgz0B~~6h zO_`L?%X$e}Tn9!8eYYqauoC){0(8)@jx2vXvW|*LbFoiS8eP@)-n*(Sq?CSROI}FH z=YAol0rla^&c}=8Z6-5oD$g7KkjA<1 zdEr*qLgV&p)f;(FRr3|a+V)$_NrxooVxJ~7+R*lL357P4jIkxthOGWdP6O)0m7R|l z%deOuZPPi;#`?rgd5PW7XN%Xie~vw-2nC}w5uwQ_g(5T+rRj^ggnnb$GYng3rkAFB zX|k8bZ6tsFPUmmRiG2{Ir>z&bMB@?#C7O_EQlgMVQxZ)}6qablORshppNDWr(+-++ z(72W4$DEh=OCayMU7nZ14+8%e`MKN8mPL>8IxFVP#Xe(mGNtY1*_=!%8DmSPl&n4= zrvdfh%Ff4&RvUB~RX0hU}ZIZNn zolU}Kd0UOO>6BH|#_TtVQT=shbKNnf&5vo}PO~Y)-GAh(te7ts`+QN`dw)^M6o1O< zZ{)0@Qpnh)c00dPb3h9@YIC-b;>O5-AI4L1DODvg(tL&EVKI?&xbBup!Y2Imu5g!? ygz*a{MNtMz>YM7$#+7aMZ + + + + + + + + + + Builds, tests, and runs the project VirtualAgentUI. + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf new file mode 100644 index 000000000..328e8e5bc --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml new file mode 100644 index 000000000..112454207 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties new file mode 100644 index 000000000..a6df38fd8 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=e60df945 +build.xml.script.CRC32=7c331eea +build.xml.stylesheet.CRC32=8064a381@1.75.2.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=e60df945 +nbproject/build-impl.xml.script.CRC32=4fa004f7 +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties new file mode 100644 index 000000000..e59ac1df6 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.properties @@ -0,0 +1,2 @@ +compile.on.save=true +user.properties.file=/home/charitha/.netbeans/8.0.2/build.properties diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml new file mode 100644 index 000000000..2f9a6910b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/private/private.xml @@ -0,0 +1,9 @@ + + + + + + file:/home/charitha/git/IoT/iot-server-agents/FireAlarmVirtualAgent/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties new file mode 100644 index 000000000..fb798f614 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.properties @@ -0,0 +1,73 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processor.options= +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/VirtualAgentUI.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.8 +javac.target=1.8 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=org.wso2.carbon.device.mgt.iot.agent.virtual.VirtualAgentUI +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml new file mode 100644 index 000000000..438f1e6a3 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + VirtualAgentUI + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/bulb-on.jpg b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/bulb-on.jpg new file mode 100644 index 0000000000000000000000000000000000000000..51d40cd834db53f1bf305997832ad4c5f7a00356 GIT binary patch literal 6942 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java new file mode 100644 index 000000000..a2aa2116a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/VirtualAgentUI.java @@ -0,0 +1,37 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.wso2.carbon.device.mgt.iot.agent.virtual; + +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.wso2.carbon.device.mgt.iot.agent.virtual.ui.AgentUI; + +/** + * + * @author charitha + */ +public class VirtualAgentUI { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + try { + // Set System L&F + UIManager.setLookAndFeel( + UIManager.getSystemLookAndFeelClassName()); + } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { + // handle exception + } + + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + new AgentUI().setVisible(true); + } + }); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form new file mode 100644 index 000000000..23b70e036 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.form @@ -0,0 +1,803 @@ + + +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java new file mode 100644 index 000000000..470a7d8fe --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl/src/main/ui/src/org/wso2/carbon/device/mgt/iot/agent/virtual/ui/AgentUI.java @@ -0,0 +1,744 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.wso2.carbon.device.mgt.iot.agent.virtual.ui; + +/** + * + * @author charitha + */ +public class AgentUI extends javax.swing.JFrame { + + /** + * Creates new form AgentUI + */ + public AgentUI() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + lblAgentName = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jPanel1 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + pnlBulbStatus = new javax.swing.JPanel(); + jPanel2 = new javax.swing.JPanel(); + jLabel4 = new javax.swing.JLabel(); + chkbxTemperatureRandom = new javax.swing.JCheckBox(); + jSeparator1 = new javax.swing.JSeparator(); + jPanel7 = new javax.swing.JPanel(); + jLabel5 = new javax.swing.JLabel(); + txtTemperatureMin = new javax.swing.JTextField(); + jLabel6 = new javax.swing.JLabel(); + txtTemperatureMax = new javax.swing.JTextField(); + jLabel10 = new javax.swing.JLabel(); + txtTemperatureSVF = new javax.swing.JTextField(); + spinnerTemperature = new javax.swing.JSpinner(); + chkbxTemperatureSmooth = new javax.swing.JCheckBox(); + jPanel6 = new javax.swing.JPanel(); + jLabel20 = new javax.swing.JLabel(); + btnView = new javax.swing.JButton(); + btnControl = new javax.swing.JButton(); + lblStatus = new javax.swing.JLabel(); + jPanel8 = new javax.swing.JPanel(); + jLabel23 = new javax.swing.JLabel(); + chkbxHumidityRandom = new javax.swing.JCheckBox(); + jSeparator5 = new javax.swing.JSeparator(); + jPanel9 = new javax.swing.JPanel(); + jLabel24 = new javax.swing.JLabel(); + txtHumidityMin = new javax.swing.JTextField(); + jLabel25 = new javax.swing.JLabel(); + txtHumidityMax = new javax.swing.JTextField(); + txtHumiditySVF = new javax.swing.JTextField(); + jLabel11 = new javax.swing.JLabel(); + spinnerHumidity = new javax.swing.JSpinner(); + chkbxHumiditySmooth = new javax.swing.JCheckBox(); + jPanel3 = new javax.swing.JPanel(); + jLabel7 = new javax.swing.JLabel(); + spinnerInterval = new javax.swing.JSpinner(); + jLabel8 = new javax.swing.JLabel(); + jLabel9 = new javax.swing.JLabel(); + cmbProtocol = new javax.swing.JComboBox(); + jLabel12 = new javax.swing.JLabel(); + cmbInterface = new javax.swing.JComboBox(); + jPanel4 = new javax.swing.JPanel(); + chkbxEmulate = new javax.swing.JCheckBox(); + cmbPeriod = new javax.swing.JComboBox(); + jLabel1 = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setTitle("Fire Alarm Emulator"); + setResizable(false); + + lblAgentName.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N + lblAgentName.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + lblAgentName.setText("Device Name: WSO2 IoT Virtual Agent"); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel2.setText("Copyright (c) 2015, WSO2 Inc."); + + jPanel1.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel3.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel3.setText("Bulb Status"); + + pnlBulbStatus.setBackground(new java.awt.Color(220, 220, 220)); + + javax.swing.GroupLayout pnlBulbStatusLayout = new javax.swing.GroupLayout(pnlBulbStatus); + pnlBulbStatus.setLayout(pnlBulbStatusLayout); + pnlBulbStatusLayout.setHorizontalGroup( + pnlBulbStatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) + ); + pnlBulbStatusLayout.setVerticalGroup( + pnlBulbStatusLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 167, Short.MAX_VALUE) + ); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(pnlBulbStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 190, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel3) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnlBulbStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + + jPanel2.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel4.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel4.setText("Temperature"); + + chkbxTemperatureRandom.setText("Randomize Data"); + chkbxTemperatureRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureRandomActionPerformed(evt); + } + }); + + jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); + + jPanel7.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabel5.setText("Min"); + + txtTemperatureMin.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtTemperatureMin.setText("20"); + txtTemperatureMin.setEnabled(false); + txtTemperatureMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMinActionPerformed(evt); + } + }); + + jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel6.setText("Max"); + + txtTemperatureMax.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtTemperatureMax.setText("50"); + txtTemperatureMax.setEnabled(false); + txtTemperatureMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureMaxActionPerformed(evt); + } + }); + + jLabel10.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel10.setText("SV %"); + + txtTemperatureSVF.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtTemperatureSVF.setText("50"); + txtTemperatureSVF.setEnabled(false); + txtTemperatureSVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTemperatureSVFActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel7Layout = new javax.swing.GroupLayout(jPanel7); + jPanel7.setLayout(jPanel7Layout); + jPanel7Layout.setHorizontalGroup( + jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel7Layout.createSequentialGroup() + .addComponent(jLabel5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMin, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureMax, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel10) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTemperatureSVF, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel7Layout.setVerticalGroup( + jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtTemperatureMin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtTemperatureMax, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel6) + .addComponent(jLabel5) + .addComponent(jLabel10) + .addComponent(txtTemperatureSVF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(35, 35, 35)) + ); + + spinnerTemperature.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N + spinnerTemperature.setModel(new javax.swing.SpinnerNumberModel(30, 0, 100, 1)); + spinnerTemperature.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerTemperatureStateChanged(evt); + } + }); + + chkbxTemperatureSmooth.setText("Smooth Variation"); + chkbxTemperatureSmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxTemperatureSmoothActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spinnerTemperature)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(chkbxTemperatureRandom) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxTemperatureSmooth))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSeparator1) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkbxTemperatureRandom) + .addComponent(chkbxTemperatureSmooth)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerTemperature))) + .addContainerGap()) + ); + + jPanel6.setBackground(new java.awt.Color(253, 254, 209)); + + jLabel20.setText("Connection Status:"); + jLabel20.setVerticalTextPosition(javax.swing.SwingConstants.TOP); + + btnView.setText("View Device Data"); + btnView.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnViewMouseClicked(evt); + } + }); + + btnControl.setText("Control Device"); + btnControl.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnControlMouseClicked(evt); + } + }); + + lblStatus.setFont(new java.awt.Font("Cantarell", 1, 15)); // NOI18N + lblStatus.setText("Not Connected"); + + javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel6Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel20) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnControl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnView) + .addContainerGap()) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel20, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnControl) + .addComponent(lblStatus))) + .addContainerGap()) + ); + + jPanel8.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel23.setFont(new java.awt.Font("Cantarell", 0, 18)); // NOI18N + jLabel23.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel23.setText("Humidity"); + + chkbxHumidityRandom.setText("Randomize Data"); + chkbxHumidityRandom.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumidityRandomActionPerformed(evt); + } + }); + + jSeparator5.setOrientation(javax.swing.SwingConstants.VERTICAL); + + jPanel9.setBackground(new java.awt.Color(220, 220, 220)); + + jLabel24.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabel24.setText("Min"); + + txtHumidityMin.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtHumidityMin.setText("20"); + txtHumidityMin.setEnabled(false); + txtHumidityMin.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMinActionPerformed(evt); + } + }); + + jLabel25.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel25.setText("Max"); + + txtHumidityMax.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtHumidityMax.setText("50"); + txtHumidityMax.setEnabled(false); + txtHumidityMax.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumidityMaxActionPerformed(evt); + } + }); + + txtHumiditySVF.setHorizontalAlignment(javax.swing.JTextField.CENTER); + txtHumiditySVF.setText("50"); + txtHumiditySVF.setEnabled(false); + txtHumiditySVF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtHumiditySVFActionPerformed(evt); + } + }); + + jLabel11.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel11.setText("SV %"); + + javax.swing.GroupLayout jPanel9Layout = new javax.swing.GroupLayout(jPanel9); + jPanel9.setLayout(jPanel9Layout); + jPanel9Layout.setHorizontalGroup( + jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createSequentialGroup() + .addComponent(jLabel24) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumidityMin, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel25) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumidityMax, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel11) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtHumiditySVF, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel9Layout.setVerticalGroup( + jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel9Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel11) + .addComponent(txtHumiditySVF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtHumidityMin, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtHumidityMax, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel25) + .addComponent(jLabel24))) + .addGap(35, 35, 35)) + ); + + spinnerHumidity.setFont(new java.awt.Font("Cantarell", 1, 24)); // NOI18N + spinnerHumidity.setModel(new javax.swing.SpinnerNumberModel(30, 0, 100, 1)); + spinnerHumidity.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerHumidityStateChanged(evt); + } + }); + + chkbxHumiditySmooth.setText("Smooth Variation"); + chkbxHumiditySmooth.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxHumiditySmoothActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel8Layout = new javax.swing.GroupLayout(jPanel8); + jPanel8.setLayout(jPanel8Layout); + jPanel8Layout.setHorizontalGroup( + jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spinnerHumidity)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(chkbxHumidityRandom) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkbxHumiditySmooth))) + .addContainerGap()) + ); + jPanel8Layout.setVerticalGroup( + jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel8Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSeparator5) + .addGroup(jPanel8Layout.createSequentialGroup() + .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkbxHumidityRandom) + .addComponent(chkbxHumiditySmooth)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 1, Short.MAX_VALUE)) + .addGroup(jPanel8Layout.createSequentialGroup() + .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerHumidity))) + .addContainerGap()) + ); + + jPanel3.setBackground(new java.awt.Color(207, 233, 234)); + + jLabel7.setText("Data Push Interval:"); + + spinnerInterval.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(5), Integer.valueOf(1), null, Integer.valueOf(1))); + spinnerInterval.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerIntervalStateChanged(evt); + } + }); + + jLabel8.setText("Seconds"); + + jLabel9.setText("Protocol:"); + + cmbProtocol.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "MQTT", "XMPP", "HTTP" })); + cmbProtocol.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbProtocolActionPerformed(evt); + } + }); + + jLabel12.setText("Interface:"); + + cmbInterface.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "eth0" })); + cmbInterface.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbInterfaceActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel7) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerInterval, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel8) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel12) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbInterface, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel9) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbProtocol, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel12) + .addComponent(cmbInterface, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel7) + .addComponent(spinnerInterval, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel8) + .addComponent(jLabel9) + .addComponent(cmbProtocol, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + jPanel4.setBackground(new java.awt.Color(169, 253, 173)); + + chkbxEmulate.setText("Emulate data"); + chkbxEmulate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkbxEmulateActionPerformed(evt); + } + }); + + cmbPeriod.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1 hour", "1 day", "1 week", "1 month " })); + cmbPeriod.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cmbPeriodActionPerformed(evt); + } + }); + + jLabel1.setText("Emulation Period"); + + javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addComponent(chkbxEmulate) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkbxEmulate) + .addComponent(cmbPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1)) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblAgentName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel8, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAgentName, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel8, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void btnControlMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnControlMouseClicked + // TODO add your handling code here: + }//GEN-LAST:event_btnControlMouseClicked + + private void btnViewMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnViewMouseClicked + // TODO add your handling code here: + }//GEN-LAST:event_btnViewMouseClicked + + private void chkbxTemperatureRandomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxTemperatureRandomActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxTemperatureRandomActionPerformed + + private void chkbxHumidityRandomActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxHumidityRandomActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxHumidityRandomActionPerformed + + private void spinnerTemperatureStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerTemperatureStateChanged + // TODO add your handling code here: + }//GEN-LAST:event_spinnerTemperatureStateChanged + + private void spinnerHumidityStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerHumidityStateChanged + // TODO add your handling code here: + }//GEN-LAST:event_spinnerHumidityStateChanged + + private void txtTemperatureMinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureMinActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTemperatureMinActionPerformed + + private void txtTemperatureMaxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureMaxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTemperatureMaxActionPerformed + + private void txtHumidityMinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumidityMinActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtHumidityMinActionPerformed + + private void txtHumidityMaxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumidityMaxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtHumidityMaxActionPerformed + + private void spinnerIntervalStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerIntervalStateChanged + // TODO add your handling code here: + }//GEN-LAST:event_spinnerIntervalStateChanged + + private void cmbInterfaceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbInterfaceActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cmbInterfaceActionPerformed + + private void cmbProtocolActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbProtocolActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cmbProtocolActionPerformed + + private void txtTemperatureSVFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTemperatureSVFActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTemperatureSVFActionPerformed + + private void txtHumiditySVFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtHumiditySVFActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtHumiditySVFActionPerformed + + private void chkbxTemperatureSmoothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxTemperatureSmoothActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxTemperatureSmoothActionPerformed + + private void chkbxHumiditySmoothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxHumiditySmoothActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxHumiditySmoothActionPerformed + + private void cmbPeriodActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbPeriodActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cmbPeriodActionPerformed + + private void chkbxEmulateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkbxEmulateActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkbxEmulateActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnControl; + private javax.swing.JButton btnView; + private javax.swing.JCheckBox chkbxEmulate; + private javax.swing.JCheckBox chkbxHumidityRandom; + private javax.swing.JCheckBox chkbxHumiditySmooth; + private javax.swing.JCheckBox chkbxTemperatureRandom; + private javax.swing.JCheckBox chkbxTemperatureSmooth; + private javax.swing.JComboBox cmbInterface; + private javax.swing.JComboBox cmbPeriod; + private javax.swing.JComboBox cmbProtocol; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel10; + private javax.swing.JLabel jLabel11; + private javax.swing.JLabel jLabel12; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel20; + private javax.swing.JLabel jLabel23; + private javax.swing.JLabel jLabel24; + private javax.swing.JLabel jLabel25; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JLabel jLabel8; + private javax.swing.JLabel jLabel9; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JPanel jPanel6; + private javax.swing.JPanel jPanel7; + private javax.swing.JPanel jPanel8; + private javax.swing.JPanel jPanel9; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JSeparator jSeparator5; + private javax.swing.JLabel lblAgentName; + private javax.swing.JLabel lblStatus; + private javax.swing.JPanel pnlBulbStatus; + private javax.swing.JSpinner spinnerHumidity; + private javax.swing.JSpinner spinnerInterval; + private javax.swing.JSpinner spinnerTemperature; + private javax.swing.JTextField txtHumidityMax; + private javax.swing.JTextField txtHumidityMin; + private javax.swing.JTextField txtHumiditySVF; + private javax.swing.JTextField txtTemperatureMax; + private javax.swing.JTextField txtTemperatureMin; + private javax.swing.JTextField txtTemperatureSVF; + // End of variables declaration//GEN-END:variables +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/build.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/build.xml new file mode 100644 index 000000000..a877b1141 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/build.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/pom.xml new file mode 100644 index 000000000..da9f26ab7 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/pom.xml @@ -0,0 +1,92 @@ + + + + + + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics + WSO2 Carbon - IoT Server Virtual Firealarm Analytics capp + pom + + + + + maven-clean-plugin + 2.4.1 + + + auto-clean + initialize + + clean + + + + + + maven-antrun-plugin + 1.7 + + + process-resources + + + + + + + run + + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/assembly/src.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/assembly/src.xml new file mode 100644 index 000000000..a5a375010 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.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/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml new file mode 100644 index 000000000..28b710c27 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml @@ -0,0 +1,26 @@ + + + + + + false + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..25df56734 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + EventReceiver_temperature.xml + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..ccfb3b314 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + org_wso2_iot_devices_temperature.xml + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml new file mode 100644 index 000000000..d06f73b14 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.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/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml new file mode 100644 index 000000000..27ec69702 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org.wso2.iot.devices.temperature_1.0.0.json + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.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 000000000..5d94b9821 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json @@ -0,0 +1,20 @@ +{ + "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/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml new file mode 100644 index 000000000..41938dd4f --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml @@ -0,0 +1,31 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 000000000..9b4228e30 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,22 @@ + + + + + Temperature_Sensor_Script.xml + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml new file mode 100644 index 000000000..c4580f909 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/pom.xml new file mode 100644 index 000000000..f9a2c1abc --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/pom.xml @@ -0,0 +1,262 @@ + + + + + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl + war + WSO2 Carbon - IoT Server VirtualFireAlarm API + WSO2 Carbon - Virtual FireAlarm Service Controller API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2 + commons-codec + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + provided + + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + virtual_firealarm + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/VirtualFireAlarmControllerService.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/VirtualFireAlarmControllerService.java new file mode 100644 index 000000000..1318caf7f --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/VirtualFireAlarmControllerService.java @@ -0,0 +1,614 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.certificate.mgt.core.dto.SCEPResponse; +import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; +import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.common.AnalyticsDataRecord; +import org.wso2.carbon.device.mgt.analytics.exception.DeviceManagementAnalyticsException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +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 org.wso2.carbon.device.mgt.iot.service.IoTServerStartupListener; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.dto.DeviceData; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.dto.SensorData; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.exception.VirtualFireAlarmException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.transport.VirtualFireAlarmMQTTConnector; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.transport.VirtualFireAlarmXMPPConnector; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.SecurityManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.VirtualFireAlarmServiceUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.scep.ContentType; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.scep.SCEPOperation; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import javax.servlet.http.HttpServletRequest; +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.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.InputStream; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This class consists the functions/APIs specific to the "actions" of the VirtualFirealarm device-type. These APIs + * include the ones that are used by the [Device] to contact the server (i.e: Enrollment & Publishing Data) and the + * ones used by the [Server/Owner] to contact the [Device] (i.e: sending control signals). This class also initializes + * the transport 'Connectors' [XMPP & MQTT] specific to the VirtualFirealarm device-type in order to communicate with + * such devices and to receive messages form it. + */ +@API(name = "virtual_firealarm", version = "1.0.0", context = "/virtual_firealarm", tags = "virtual_firealarm") +@DeviceType(value = "virtual_firealarm") +@SuppressWarnings("Non-Annoted WebService") +public class VirtualFireAlarmControllerService { + + private static final String XMPP_PROTOCOL = "XMPP"; + private static final String HTTP_PROTOCOL = "HTTP"; + private static final String MQTT_PROTOCOL = "MQTT"; + private static Log log = LogFactory.getLog(VirtualFireAlarmControllerService.class); + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + // consists of utility methods related to encrypting and decrypting messages + private SecurityManager securityManager; + // connects to the given MQTT broker and handles MQTT communication + private VirtualFireAlarmMQTTConnector virtualFireAlarmMQTTConnector; + // connects to the given XMPP server and handles XMPP communication + private VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector; + // holds a mapping of the IP addresses to Device-IDs for HTTP communication + private ConcurrentHashMap deviceToIpMap = new ConcurrentHashMap<>(); + + private boolean waitForServerStartup() { + while (!IoTServerStartupListener.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + /** + * Fetches the `SecurityManager` specific to this VirtualFirealarm controller service. + * + * @return the 'SecurityManager' instance bound to the 'securityManager' variable of this service. + */ + @SuppressWarnings("Unused") + public SecurityManager getSecurityManager() { + return securityManager; + } + + /** + * Sets the `securityManager` variable of this VirtualFirealarm controller service. + * + * @param securityManager a 'SecurityManager' object that handles the encryption, decryption, signing and validation + * of incoming messages from VirtualFirealarm device-types. + */ + @SuppressWarnings("Unused") + public void setSecurityManager(SecurityManager securityManager) { + this.securityManager = securityManager; + securityManager.initVerificationManager(); + } + + /** + * Fetches the `VirtualFireAlarmXMPPConnector` specific to this VirtualFirealarm controller service. + * + * @return the 'VirtualFireAlarmXMPPConnector' instance bound to the 'virtualFireAlarmXMPPConnector' variable of + * this service. + */ + @SuppressWarnings("Unused") + public VirtualFireAlarmXMPPConnector getVirtualFireAlarmXMPPConnector() { + return virtualFireAlarmXMPPConnector; + } + + /** + * Sets the `virtualFireAlarmXMPPConnector` variable of this VirtualFirealarm controller service. + * + * @param virtualFireAlarmXMPPConnector a 'VirtualFireAlarmXMPPConnector' object that handles all XMPP related + * communications of any connected VirtualFirealarm device-type + */ + @SuppressWarnings("Unused") + public void setVirtualFireAlarmXMPPConnector( + final VirtualFireAlarmXMPPConnector virtualFireAlarmXMPPConnector) { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + VirtualFireAlarmControllerService.this.virtualFireAlarmXMPPConnector = virtualFireAlarmXMPPConnector; + + if (XmppConfig.getInstance().isEnabled()) { + Runnable xmppStarter = new Runnable() { + @Override + public void run() { + virtualFireAlarmXMPPConnector.initConnector(); + virtualFireAlarmXMPPConnector.connect(); + } + }; + + Thread xmppStarterThread = new Thread(xmppStarter); + xmppStarterThread.setDaemon(true); + xmppStarterThread.start(); + } else { + log.warn("XMPP disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmXMPPConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + /** + * Fetches the `VirtualFireAlarmMQTTConnector` specific to this VirtualFirealarm controller service. + * + * @return the 'VirtualFireAlarmMQTTConnector' instance bound to the 'virtualFireAlarmMQTTConnector' variable of + * this service. + */ + @SuppressWarnings("Unused") + public VirtualFireAlarmMQTTConnector getVirtualFireAlarmMQTTConnector() { + return virtualFireAlarmMQTTConnector; + } + + /** + * Sets the `virtualFireAlarmMQTTConnector` variable of this VirtualFirealarm controller service. + * + * @param virtualFireAlarmMQTTConnector a 'VirtualFireAlarmMQTTConnector' object that handles all MQTT related + * communications of any connected VirtualFirealarm device-type + */ + @SuppressWarnings("Unused") + public void setVirtualFireAlarmMQTTConnector( + final VirtualFireAlarmMQTTConnector virtualFireAlarmMQTTConnector) { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + VirtualFireAlarmControllerService.this.virtualFireAlarmMQTTConnector = virtualFireAlarmMQTTConnector; + if (MqttConfig.getInstance().isEnabled()) { + virtualFireAlarmMQTTConnector.connect(); + } else { + log.warn("MQTT disabled in 'devicemgt-config.xml'. Hence, VirtualFireAlarmMQTTConnector not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + /** + * This is an API used/called by the device. It registers the IP of a VirtualFirealarm device against its DeviceID + * when the device connects with the server for the first time. This DeviceID to IP mapping is necessary only for + * cases where HTTP communication is to be used. At such instances, this mapping is used by the server to + * identify the IP of the device to which it has some message to be sent. This method becomes useful only in + * scenarios where HTTP communication is used in a setup where the IoT-Server and the devices communicating with it + * are in the same IP network. + * + * @param deviceId the ID of the VirtualFirealarm device from which this register-IP call was initiated. + * @param deviceIP the IP of the VirtualFirealarm device which has sent this register-IP request. + * @param devicePort the PORT on the VirtualFirealarm device (on this IP) that's open for HTTP communication. + * @param request the HTTP servlet request object received by default as part of the HTTP call to this API. + * @param response the HTTP servlet response object received by default as part of the HTTP call to this API. + * @return a custom message indicating whether the DeviceID to IP mapping was successful. + */ + @POST + @Path("controller/register/{deviceId}/{ip}/{port}") + public String registerDeviceIP(@PathParam("deviceId") String deviceId, @PathParam("ip") String deviceIP, + @PathParam("port") String devicePort, @Context HttpServletRequest request, + @Context HttpServletResponse response) { + try { + String result; + if (log.isDebugEnabled()) { + log.debug("Got register call from IP: " + deviceIP + " for Device ID: " + deviceId); + } + String deviceHttpEndpoint = deviceIP + ":" + devicePort; + deviceToIpMap.put(deviceId, deviceHttpEndpoint); + result = "Device-IP Registered"; + response.setStatus(Response.Status.OK.getStatusCode()); + if (log.isDebugEnabled()) { + log.debug(result); + } + return result; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * This is an API called/used from within the Server(Front-End) or by a device Owner. It sends a control command to + * the VirtualFirealarm device to switch `ON` or `OFF` its buzzer. The method also takes in the protocol to be used + * to connect-to and send the command to the device. + * + * @param deviceId the ID of the VirtualFirealarm device on which the buzzer needs to switched `ON` or `OFF`. + * @param protocol the protocol (HTTP, MQTT, XMPP) to be used to connect-to & send the message to the device. + * @param state the state to which the buzzer on the device needs to be changed. Either "ON" or "OFF". + * (Case-Insensitive String) + * @param response the HTTP servlet response object received by default as part of the HTTP call to this API. + */ + @POST + @Path("controller/device/{deviceId}/buzz/") + @Feature(code = "buzz", name = "Buzzer On / Off", type = "operation", + description = "Switch on/off Virtual Fire Alarm Buzzer. (On / Off)") + public void switchBuzzer(@PathParam("deviceId") String deviceId, @QueryParam("protocol") String protocol, + @FormParam("state") String state, @Context HttpServletResponse response) { + String switchToState = state.toUpperCase(); + if (!switchToState.equals(VirtualFireAlarmConstants.STATE_ON) && !switchToState.equals( + VirtualFireAlarmConstants.STATE_OFF)) { + log.error("The requested state change shoud be either - 'ON' or 'OFF'"); + response.setStatus(Response.Status.BAD_REQUEST.getStatusCode()); + return; + } + String protocolString = protocol.toUpperCase(); + String callUrlPattern = VirtualFireAlarmConstants.BULB_CONTEXT + switchToState; + if (log.isDebugEnabled()) { + log.debug("Sending request to switch-bulb of device [" + deviceId + "] via " + + protocolString); + } + try { + switch (protocolString) { + case HTTP_PROTOCOL: + String deviceHTTPEndpoint = deviceToIpMap.get(deviceId); + if (deviceHTTPEndpoint == null) { + response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); + return; + } + VirtualFireAlarmServiceUtils.sendCommandViaHTTP(deviceHTTPEndpoint, callUrlPattern, true); + break; + case XMPP_PROTOCOL: + String xmppResource = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", ""); + virtualFireAlarmXMPPConnector.publishDeviceData(deviceId, xmppResource, switchToState); + break; + default: + String mqttResource = VirtualFireAlarmConstants.BULB_CONTEXT.replace("/", ""); + virtualFireAlarmMQTTConnector.publishDeviceData(deviceId, mqttResource, switchToState); + break; + } + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException | TransportHandlerException e) { + log.error("Failed to send switch-bulb request to device [" + deviceId + "] via " + protocolString); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * This is an API called/used from within the Server(Front-End) or by a device Owner. It sends a control command + * to the VirtualFirealarm device to 'tell what's its current temperature reading'. The method also takes in the + * protocol to be used to connect-to and send the command to the device. + * + * @param deviceId the ID of the VirtualFirealarm device on which the temperature reading is be read-from. + * @param protocol the protocol (HTTP, MQTT, XMPP) to be used to connect-to & send the message to the device. + * @param response the HTTP servlet response object received by default as part of the HTTP call to this API. + * @return an instance of the 'SensorRecord' object that holds the last updated temperature of the VirtualFirealarm + * whose temperature reading was requested. + */ + @GET + @Path("controller/device/{deviceId}/temperature") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Feature(code = "temperature", name = "Temperature", type = "monitor", + description = "Request Temperature reading from Virtual Fire Alarm") + public SensorRecord requestTemperature(@PathParam("deviceId") String deviceId, + @QueryParam("protocol") String protocol, + @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + String protocolString = protocol.toUpperCase(); + if (log.isDebugEnabled()) { + log.debug("Sending request to read virtual-firealarm-temperature of device " + + "[" + deviceId + "] via " + protocolString); + } + try { + switch (protocolString) { + case HTTP_PROTOCOL: + String deviceHTTPEndpoint = deviceToIpMap.get(deviceId); + if (deviceHTTPEndpoint == null) { + response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); + } + String temperatureValue = VirtualFireAlarmServiceUtils.sendCommandViaHTTP( + deviceHTTPEndpoint, VirtualFireAlarmConstants.TEMPERATURE_CONTEXT, false); + SensorDataManager.getInstance().setSensorRecord(deviceId, VirtualFireAlarmConstants.SENSOR_TEMP, + temperatureValue, + Calendar.getInstance().getTimeInMillis()); + break; + case XMPP_PROTOCOL: + String xmppResource = VirtualFireAlarmConstants.TEMPERATURE_CONTEXT.replace("/", ""); + virtualFireAlarmMQTTConnector.publishDeviceData(deviceId, xmppResource, ""); + break; + default: + String mqttResource = VirtualFireAlarmConstants.TEMPERATURE_CONTEXT.replace("/", ""); + virtualFireAlarmMQTTConnector.publishDeviceData(deviceId, mqttResource, ""); + break; + } + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, VirtualFireAlarmConstants + .SENSOR_TEMP); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException | DeviceControllerException | TransportHandlerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + return sensorRecord; + } + + /** + * This is an API called/used by the VirtualFirealarm device to publish its temperature to the IoT-Server. The + * received data from the device is stored in a 'DeviceRecord' under the device's ID in the 'SensorDataManager' + * of the Server. + * + * @param dataMsg the temperature data received from the device in JSON format complying to type 'DeviceData'. + * @param response the HTTP servlet response object received by default as part of the HTTP call to this API. + */ + @POST + @Path("controller/temperature") + @Consumes(MediaType.APPLICATION_JSON) + public void pushTemperatureData(final DeviceData dataMsg, @Context HttpServletResponse response) { + try { + String deviceId = dataMsg.deviceId; + String deviceIp = dataMsg.reply; + float temperature = dataMsg.value; + String registeredIp = deviceToIpMap.get(deviceId); + if (registeredIp == null) { + log.warn("Unregistered IP: Temperature Data Received from an un-registered IP " + + deviceIp + " for device ID - " + deviceId); + response.setStatus(Response.Status.PRECONDITION_FAILED.getStatusCode()); + return; + } else if (!registeredIp.equals(deviceIp)) { + log.warn("Conflicting IP: Received IP is " + deviceIp + ". Device with ID " + deviceId + + " is already registered under some other IP. Re-registration required"); + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return; + } + SensorDataManager.getInstance().setSensorRecord(deviceId, VirtualFireAlarmConstants.SENSOR_TEMP, + String.valueOf(temperature), + Calendar.getInstance().getTimeInMillis()); + if (!VirtualFireAlarmServiceUtils.publishToDAS(dataMsg.deviceId, dataMsg.value)) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * This is an API called/used by the SCEP Client of the VirtualFirealarm device in its SCEP enrollment process. + * This acts as the endpoint exposed as part of the SCEP-Server for use by a SCEP Client. This is one of the two + * method-signatures that takes different parameters according to the SCEP-Operation executed by the SCEP-Client + * of the enrolling device. The API supports 2 SCEP Operations [GetCACert] and [GetCACaps]. + *

      + * Operation [GetCACert] returns the CA cert of the SCEP-Server for the device to verify its authenticity. + * Operation [GetCACaps] returns the CA Capabilities of the SCEP-Server. + * + * @param operation the SCEP operation requested by the client. [GetCACert] or [GetCACaps] + * @param message any messages pertaining to the requested SCEP Operation. + * @return an HTTP Response object with either the CA-Cert or the CA-Capabilities according to the operation. + */ + @GET + @Path("controller/scep") + public Response scepRequest(@QueryParam("operation") String operation, @QueryParam("message") String message) { + try { + if (log.isDebugEnabled()) { + log.debug("Invoking SCEP operation " + operation); + } + if (SCEPOperation.GET_CA_CERT.getValue().equals(operation)) { + if (log.isDebugEnabled()) { + log.debug("Invoking GetCACert"); + } + try { + CertificateManagementService certificateManagementService = + VirtualFireAlarmServiceUtils.getCertificateManagementService(); + SCEPResponse scepResponse = certificateManagementService.getCACertSCEP(); + Response.ResponseBuilder responseBuilder; + switch (scepResponse.getResultCriteria()) { + case CA_CERT_FAILED: + log.error("CA cert failed"); + responseBuilder = Response.serverError(); + break; + case CA_CERT_RECEIVED: + if (log.isDebugEnabled()) { + log.debug("CA certificate received in GetCACert"); + } + responseBuilder = Response.ok(scepResponse.getEncodedResponse(), + ContentType.X_X509_CA_CERT); + break; + case CA_RA_CERT_RECEIVED: + if (log.isDebugEnabled()) { + log.debug("CA and RA certificates received in GetCACert"); + } + responseBuilder = Response.ok(scepResponse.getEncodedResponse(), + ContentType.X_X509_CA_RA_CERT); + break; + default: + log.error("Invalid SCEP request"); + responseBuilder = Response.serverError(); + break; + } + + return responseBuilder.build(); + } catch (VirtualFireAlarmException e) { + log.error("Error occurred while enrolling the VirtualFireAlarm device", e); + } catch (KeystoreException e) { + log.error("Keystore error occurred while enrolling the VirtualFireAlarm device", e); + } + + } else if (SCEPOperation.GET_CA_CAPS.getValue().equals(operation)) { + + if (log.isDebugEnabled()) { + log.debug("Invoking GetCACaps"); + } + + try { + CertificateManagementService certificateManagementService = VirtualFireAlarmServiceUtils. + getCertificateManagementService(); + byte caCaps[] = certificateManagementService.getCACapsSCEP(); + + return Response.ok(caCaps, MediaType.TEXT_PLAIN).build(); + + } catch (VirtualFireAlarmException e) { + log.error("Error occurred while enrolling the device", e); + } + + } else { + log.error("Invalid SCEP operation " + operation); + } + + return Response.serverError().build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * This is an API called/used by the SCEP Client of the VirtualFirealarm device in its SCEP enrollment process. + * This acts as the endpoint exposed as part of the SCEP-Server for use by a SCEP Client. This is one of the two + * method-signatures that takes different parameters according to the SCEP-Operation executed by the SCEP-Client + * of the enrolling device. This API supports the SCEP Operation [PKIOperation]. + *

      + * Operation [PKIOperation] returns a certificate generated by the SCEP-Server for the enrolling device. + * + * @param operation the final SCEP operation executed in the enrollment process - which is [PKIOperation] + * @param inputStream an input stream consisting of the Certificate-Signing-Request (CSR) from the device. + * @return an HTTP Response object with the signed certificate for the device by the CA of the SCEP Server. + */ + @POST + @Path("controller/scep") + public Response scepRequestPost(@QueryParam("operation") String operation, InputStream inputStream) { + try { + if (log.isDebugEnabled()) { + log.debug("Invoking SCEP operation " + operation); + } + if (SCEPOperation.PKI_OPERATION.getValue().equals(operation)) { + if (log.isDebugEnabled()) { + log.debug("Invoking PKIOperation"); + } + try { + CertificateManagementService certificateManagementService = VirtualFireAlarmServiceUtils. + getCertificateManagementService(); + byte pkiMessage[] = certificateManagementService.getPKIMessageSCEP(inputStream); + return Response.ok(pkiMessage, ContentType.X_PKI_MESSAGE).build(); + } catch (VirtualFireAlarmException e) { + log.error("Error occurred while enrolling the device", e); + } catch (KeystoreException e) { + log.error("Keystore error occurred while enrolling the device", e); + } + } + return Response.serverError().build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Retreive Sensor data for the device type + */ + @Path("controller/stats/device/{deviceId}/sensors/{sensorName}") + @GET + @Consumes("application/json") + @Produces("application/json") + public SensorData[] getVirtualFirealarmStats(@PathParam("deviceId") String deviceId, @PathParam("sensorName") String sensor, + @QueryParam("username") String user, @QueryParam("from") long from, + @QueryParam("to") long to) { + try { + String fromDate = String.valueOf(from); + String toDate = String.valueOf(to); + List sensorDatas = new ArrayList<>(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx + .getOSGiService(DeviceAnalyticsService.class, null); + String query = "owner:" + user + " AND deviceId:" + deviceId + " AND deviceType:" + + VirtualFireAlarmConstants.DEVICE_TYPE + " AND time : [" + fromDate + " TO " + toDate + "]"; + String sensorTableName = getSensorEventTableName(sensor); + if (sensorTableName != null) { + List records = deviceAnalyticsService.getAllEventsForDevice(sensorTableName, query); + Collections.sort(records, new Comparator() { + @Override + public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { + long t1 = (Long) o1.getValue("time"); + long t2 = (Long) o2.getValue("time"); + if (t1 < t2) { + return -1; + } else if (t1 > t2) { + return 1; + } else { + return 0; + } + } + }); + for (AnalyticsDataRecord record : records) { + SensorData sensorData = new SensorData(); + sensorData.setTime((long) record.getValue("time")); + sensorData.setValue("" + (float) record.getValue(sensor)); + sensorDatas.add(sensorData); + } + return sensorDatas.toArray(new SensorData[sensorDatas.size()]); + } + } catch (DeviceManagementAnalyticsException e) { + String errorMsg = "Error on retrieving stats on table for sensor name" + sensor; + log.error(errorMsg); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + return new SensorData[0]; + } + + /** + * get the event table from the sensor name. + */ + private String getSensorEventTableName(String sensorName){ + String sensorEventTableName; + switch (sensorName) { + case VirtualFireAlarmConstants.SENSOR_TEMP: + sensorEventTableName = VirtualFireAlarmConstants.TEMPERATURE_EVENT_TABLE; + break; + case VirtualFireAlarmConstants.SENSOR_HUMIDITY: + sensorEventTableName = VirtualFireAlarmConstants.HUMIDITY_EVENT_TABLE; + break; + default: + sensorEventTableName = null; + } + return sensorEventTableName; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/DeviceData.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/DeviceData.java new file mode 100644 index 000000000..a6dde796b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/DeviceData.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceData { + @XmlElement(required = true) public String owner; + @XmlElement(required = true) public String deviceId; + @XmlElement(required = true) public String reply; + @XmlElement public Long time; + @XmlElement public String key; + @XmlElement public float value; +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/SensorData.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/SensorData.java new file mode 100644 index 000000000..a4792fca7 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/dto/SensorData.java @@ -0,0 +1,44 @@ +package org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +/** + * This stores sensor event data for the device type. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class SensorData { + + @XmlElement public Long time; + @XmlElement public String key; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + @XmlElement public String value; + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/exception/VirtualFireAlarmException.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/exception/VirtualFireAlarmException.java new file mode 100644 index 000000000..4dd6faacb --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/exception/VirtualFireAlarmException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.exception; + +public class VirtualFireAlarmException extends Exception { + private static final long serialVersionUID = 118512086957330189L; + + public VirtualFireAlarmException(String errorMessage) { + super(errorMessage); + } + + public VirtualFireAlarmException(String errorMessage, Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmMQTTConnector.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmMQTTConnector.java new file mode 100644 index 000000000..05c0a459e --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmMQTTConnector.java @@ -0,0 +1,309 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.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.wso2.carbon.context.PrivilegedCarbonContext; +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.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +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 org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.exception.VirtualFireAlarmException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.SecurityManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.VirtualFireAlarmServiceUtils; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Calendar; +import java.util.UUID; + +/** + * This is an example for the use of the MQTT capabilities provided by the IoT-Server. This example depicts the use + * of MQTT Transport for the VirtualFirealarm device-type. This class extends the abstract class + * "MQTTTransportHandler". "MQTTTransportHandler" consists of the MQTT client specific functionality and implements + * the "TransportHandler" interface. The actual functionality related to the "TransportHandler" interface is + * implemented here, in this concrete class. Whilst the abstract class "MQTTTransportHandler" is intended to provide + * the common MQTT functionality, this class (which is its extension) provides the implementation specific to the + * MQTT communication of the Device-Type (VirtualFirealarm) in concern. + *

      + * Hence, the methods of this class are implementation of the "TransportHandler" interface which handles the device + * specific logic to connect-to, publish-to, process-incoming-messages-from and disconnect-from the MQTT broker + * listed in the configurations. + */ +@SuppressWarnings("no JAX-WS annotation") +public class VirtualFireAlarmMQTTConnector extends MQTTTransportHandler { + + private static Log log = LogFactory.getLog(VirtualFireAlarmMQTTConnector.class); + // subscription topic: /+/virtual_firealarm/+/publisher + // wildcard (+) is in place for device_owner & device_id + private static String subscribeTopic = "wso2/" + VirtualFireAlarmConstants.DEVICE_TYPE + "/+/publisher"; + private static String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5); + + /** + * Default constructor for the VirtualFirealarmMQTTConnector. + */ + private VirtualFireAlarmMQTTConnector() { + super(iotServerSubscriber, VirtualFireAlarmConstants.DEVICE_TYPE, + MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic); + } + + /** + * {@inheritDoc} + * VirtualFirealarm device-type specific implementation to connect to the MQTT broker and subscribe to a topic. + * This method is called to initiate a MQTT communication. + */ + @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(); + } + + /** + * {@inheritDoc} + * VirtualFirealarm device-type specific implementation to process incoming messages. This is the specific + * method signature of the overloaded "processIncomingMessage" method that gets called from the messageArrived() + * callback of the "MQTTTransportHandler". + */ + @Override + public void processIncomingMessage(MqttMessage mqttMessage, String... messageParams) { + if (messageParams.length != 0) { + // owner and the deviceId are extracted from the MQTT topic to which the message was received. + // = [ServerName/Owner/DeviceType/DeviceId/"publisher"] + String topic = messageParams[0]; + String[] topicParams = topic.split("/"); + String deviceId = topicParams[2]; + if (log.isDebugEnabled()) { + log.debug("Received MQTT message for: [DEVICE.ID-" + deviceId + "]"); + } + + String actualMessage; + try { + // the hash-code of the deviceId is used as the alias for device certificates during SCEP enrollment. + // hence, the same is used here to fetch the device-specific-certificate from the key store. + PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId); + PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey(); + + // the MQTT-messages from VirtualFireAlarm devices are in the form {"Msg":, "Sig":} + actualMessage = VirtualFireAlarmServiceUtils.extractMessageFromPayload(mqttMessage.toString(), + serverPrivateKey, + clientPublicKey); + if (log.isDebugEnabled()) { + log.debug("MQTT: Received Message [" + actualMessage + "] topic: [" + topic + "]"); + } + + if (actualMessage.contains("PUBLISHER")) { + float temperature = Float.parseFloat(actualMessage.split(":")[2]); + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceManagementProviderService deviceManagementProviderService = + (DeviceManagementProviderService) ctx + .getOSGiService(DeviceManagementProviderService.class, null); + if (deviceManagementProviderService != null) { + DeviceIdentifier identifier = new DeviceIdentifier(deviceId, + VirtualFireAlarmConstants.DEVICE_TYPE); + Device device = deviceManagementProviderService.getDevice(identifier); + if (device != null) { + String owner = device.getEnrolmentInfo().getOwner(); + ctx.setTenantDomain(MultitenantUtils.getTenantDomain(owner), true); + ctx.setUsername(owner); + if (!VirtualFireAlarmServiceUtils.publishToDAS(deviceId, temperature)) { + log.error("MQTT Subscriber: Publishing data to DAS failed."); + } + } + } + } catch (DeviceManagementException e) { + log.error("Failed to retreive the device managment service for device type " + + VirtualFireAlarmConstants.DEVICE_TYPE, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + if (log.isDebugEnabled()) { + log.debug("MQTT Subscriber: Published data to DAS successfully."); + } + + } else if (actualMessage.contains("TEMPERATURE")) { + String temperatureValue = actualMessage.split(":")[1]; + SensorDataManager.getInstance().setSensorRecord(deviceId, VirtualFireAlarmConstants.SENSOR_TEMP, + temperatureValue, + Calendar.getInstance().getTimeInMillis()); + } + } catch (VirtualFireAlarmException e) { + String errorMsg = + "CertificateManagementService failure oo Signature-Verification/Decryption was unsuccessful."; + log.error(errorMsg, e); + } + } else { + String errorMsg = + "MQTT message [" + mqttMessage.toString() + "] was received without the topic information."; + log.warn(errorMsg); + } + } + + /** + * {@inheritDoc} + * VirtualFirealarm device-type specific implementation to publish data to the device. This method calls the + * {@link #publishToQueue(String, MqttMessage)} method of the "MQTTTransportHandler" class. + */ + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + if (publishData.length != 4) { + String errorMsg = "Incorrect number of arguments received to SEND-MQTT Message. " + + "Need to be [owner, deviceId, resource{BULB/TEMP}, state{ON/OFF or null}]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg); + } + + String deviceOwner = publishData[0]; + String deviceId = publishData[1]; + String resource = publishData[2]; + String state = publishData[3]; + + MqttMessage pushMessage = new MqttMessage(); + String publishTopic = "wso2/" + VirtualFireAlarmConstants.DEVICE_TYPE + "/" + deviceId; + + try { + PublicKey devicePublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId); + PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey(); + + String actualMessage = resource + ":" + state; + String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage, + devicePublicKey, + serverPrivateKey); + + pushMessage.setPayload(encryptedMsg.getBytes(StandardCharsets.UTF_8)); + pushMessage.setQos(DEFAULT_MQTT_QUALITY_OF_SERVICE); + pushMessage.setRetained(false); + + publishToQueue(publishTopic, pushMessage); + + } catch (VirtualFireAlarmException e) { + String errorMsg = "Preparing Secure payload failed for device - [" + deviceId + "] of owner - " + + "[" + deviceOwner + "]."; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + } + + + /** + * {@inheritDoc} + * VirtualFirealarm device-type specific implementation to disconnect from the MQTT broker. + */ + @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 + + " for device-type - " + VirtualFireAlarmConstants.DEVICE_TYPE, e); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("MQTT-Terminator: Thread Sleep Interrupt Exception at device-type - " + + VirtualFireAlarmConstants.DEVICE_TYPE, e1); + } + } + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + + /** + * {@inheritDoc} + */ + @Override + public void publishDeviceData() { + // nothing to do + } + + /** + * {@inheritDoc} + */ + @Override + public void publishDeviceData(MqttMessage publishData) throws TransportHandlerException { + // nothing to do + } + + /** + * {@inheritDoc} + */ + @Override + public void processIncomingMessage() { + // nothing to do + } + + /** + * {@inheritDoc} + */ + @Override + public void processIncomingMessage(MqttMessage message) throws TransportHandlerException { + // nothing to do + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmXMPPConnector.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmXMPPConnector.java new file mode 100644 index 000000000..00697c81a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/transport/VirtualFireAlarmXMPPConnector.java @@ -0,0 +1,293 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jivesoftware.smack.packet.Message; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.iot.config.server.DeviceManagementConfigurationManager; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppAccount; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient; +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.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.transport.xmpp.XMPPTransportHandler; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.exception.VirtualFireAlarmException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.SecurityManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.VirtualFireAlarmServiceUtils; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.io.File; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Calendar; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +@SuppressWarnings("no JAX-WS annotation") +public class VirtualFireAlarmXMPPConnector extends XMPPTransportHandler { + private static Log log = LogFactory.getLog(VirtualFireAlarmXMPPConnector.class); + + private static String xmppServerIP; + private static String xmppVFireAlarmAdminUsername; + private static String xmppVFireAlarmAdminAccountJID; + private static final String V_FIREALARM_XMPP_PASSWORD = "vfirealarm@123"; + private static final String DEVICEMGT_CONFIG_FILE = "devicemgt-config.xml"; + + private ScheduledFuture connectorServiceHandler; + private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); + + private VirtualFireAlarmXMPPConnector() { + super(XmppConfig.getInstance().getXmppServerIP(), XmppConfig.getInstance().getSERVER_CONNECTION_PORT()); + } + + public void initConnector() { + xmppVFireAlarmAdminUsername = "wso2admin_" + VirtualFireAlarmConstants.DEVICE_TYPE; + xmppServerIP = XmppConfig.getInstance().getXmppServerIP(); + xmppVFireAlarmAdminAccountJID = xmppVFireAlarmAdminUsername + "@" + xmppServerIP; + createXMPPAccountForDeviceType(); + } + + public void createXMPPAccountForDeviceType() { + boolean accountExists; + XmppServerClient xmppServerClient = new XmppServerClient(); + xmppServerClient.initControlQueue(); + + try { + accountExists = xmppServerClient.doesXMPPUserAccountExist(xmppVFireAlarmAdminUsername); + + if (!accountExists) { + XmppAccount xmppAccount = new XmppAccount(); + + xmppAccount.setAccountName(xmppVFireAlarmAdminUsername); + xmppAccount.setUsername(xmppVFireAlarmAdminUsername); + xmppAccount.setPassword(V_FIREALARM_XMPP_PASSWORD); + xmppAccount.setEmail(""); + + try { + boolean xmppCreated = xmppServerClient.createXMPPAccount(xmppAccount); + if (!xmppCreated) { + log.warn("Server XMPP Account was not created for device-type - " + + VirtualFireAlarmConstants.DEVICE_TYPE + + ". Check whether XMPP is enabled in \"devicemgt-config.xml\" & restart."); + } else { + log.info("Server XMPP Account [" + xmppVFireAlarmAdminUsername + + "] was not created for device - " + VirtualFireAlarmConstants.DEVICE_TYPE); + } + } catch (DeviceControllerException e) { + String errorMsg = + "An error was encountered whilst trying to create Server XMPP account for device-type - " + + VirtualFireAlarmConstants.DEVICE_TYPE; + log.error(errorMsg, e); + } + } + + } catch (DeviceControllerException e) { + if (e.getMessage().contains(DEVICEMGT_CONFIG_FILE)) { + log.warn("XMPP not Enabled"); + } else { + String errorMsg = "An error was encountered whilst trying to check whether Server XMPP account " + + "exists for device-type - " + VirtualFireAlarmConstants.DEVICE_TYPE ; + log.error(errorMsg, e); + } + } + } + + + @Override + public void connect() { + Runnable connector = new Runnable() { + public void run() { + if (!isConnected()) { + try { + connectToServer(); + loginToServer(xmppVFireAlarmAdminUsername, V_FIREALARM_XMPP_PASSWORD, null); + setFilterOnReceiver(xmppVFireAlarmAdminAccountJID); + + } catch (TransportHandlerException e) { + if (log.isDebugEnabled()) { + log.warn("Connection/Login to XMPP server at: " + server + " as " + + xmppVFireAlarmAdminUsername + " failed for device-type [" + + VirtualFireAlarmConstants.DEVICE_TYPE + "].", e); + } + } + } + } + }; + + connectorServiceHandler = service.scheduleAtFixedRate(connector, 0, timeoutInterval, TimeUnit.MILLISECONDS); + } + + @Override + public void processIncomingMessage(Message xmppMessage) throws TransportHandlerException { + String from = xmppMessage.getFrom(); + String subject = xmppMessage.getSubject(); + String message = xmppMessage.getBody(); + + int indexOfAt = from.indexOf("@"); + int indexOfSlash = from.indexOf("/"); + + if (indexOfAt != -1 && indexOfSlash != -1) { + String deviceId = from.substring(0, indexOfAt); + String owner = from.substring(indexOfSlash + 1, from.length()); + + if (log.isDebugEnabled()) { + log.debug("Received XMPP message for: [OWNER-" + owner + "] & [DEVICE.ID-" + deviceId + "]"); + } + + try { + PublicKey clientPublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId); + PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey(); + String actualMessage = VirtualFireAlarmServiceUtils.extractMessageFromPayload(message, serverPrivateKey, + clientPublicKey); + if (log.isDebugEnabled()) { + log.debug("XMPP: Received Message [" + actualMessage + "] from: [" + from + "]"); + } + if (subject != null) { + switch (subject) { + case "PUBLISHER": + float temperature = Float.parseFloat(actualMessage.split(":")[1]); + PrivilegedCarbonContext.startTenantFlow(); + String tenantDomain = MultitenantUtils.getTenantDomain(owner); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(owner); + if (!VirtualFireAlarmServiceUtils.publishToDAS(deviceId, temperature)) { + log.error("XMPP Connector: Publishing VirtualFirealarm data to DAS failed."); + } + PrivilegedCarbonContext.endTenantFlow(); + if (log.isDebugEnabled()) { + log.debug("XMPP: Publisher Message [" + actualMessage + "] from [" + from + "] " + + "was successfully published to DAS"); + } + break; + case "CONTROL-REPLY": + String tempVal = actualMessage.split(":")[1]; + SensorDataManager.getInstance().setSensorRecord(deviceId, + VirtualFireAlarmConstants.SENSOR_TEMP, + tempVal, + Calendar.getInstance().getTimeInMillis()); + break; + + default: + if (log.isDebugEnabled()) { + log.warn("Unknown XMPP Message [" + actualMessage + "] from [" + from + "] received"); + } + break; + } + } + } catch (VirtualFireAlarmException e) { + String errorMsg = + "CertificateManagementService failure oo Signature-Verification/Decryption was unsuccessful."; + log.error(errorMsg, e); + } + } else { + log.warn("Received XMPP message from client with unexpected JID [" + from + "]."); + } + } + + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + if (publishData.length != 4) { + String errorMsg = "Incorrect number of arguments received to SEND-MQTT Message. " + + "Need to be [owner, deviceId, resource{BULB/TEMP}, state{ON/OFF or null}]"; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg); + } + + String deviceOwner = publishData[0]; + String deviceId = publishData[1]; + String resource = publishData[2]; + String state = publishData[3]; + + try { + PublicKey devicePublicKey = VirtualFireAlarmServiceUtils.getDevicePublicKey(deviceId); + PrivateKey serverPrivateKey = SecurityManager.getServerPrivateKey(); + + String actualMessage = resource + ":" + state; + String encryptedMsg = VirtualFireAlarmServiceUtils.prepareSecurePayLoad(actualMessage, + devicePublicKey, + serverPrivateKey); + + String clientToConnect = deviceId + "@" + xmppServerIP + File.separator + deviceOwner; + sendXMPPMessage(clientToConnect, encryptedMsg, "CONTROL-REQUEST"); + + } catch (VirtualFireAlarmException e) { + String errorMsg = "Preparing Secure payload failed for device - [" + deviceId + "] of owner - " + + "[" + deviceOwner + "]."; + log.error(errorMsg); + throw new TransportHandlerException(errorMsg, e); + } + } + + + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + connectorServiceHandler.cancel(true); + closeConnection(); + if (log.isDebugEnabled()) { + log.warn("Unable to 'STOP' connection to XMPP server at: " + server + + " for user - " + xmppVFireAlarmAdminUsername); + } + + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("XMPP-Terminator: Thread Sleep Interrupt Exception for " + + VirtualFireAlarmConstants.DEVICE_TYPE + " type.", e1); + } + + } + } + }; + + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + + @Override + public void processIncomingMessage(Message message, String... messageParams) throws TransportHandlerException { + // nothing to do + } + + @Override + public void processIncomingMessage() throws TransportHandlerException { + // nothing to do + } + + @Override + public void publishDeviceData() throws TransportHandlerException { + // nothing to do + } + + @Override + public void publishDeviceData(Message publishData) throws TransportHandlerException { + // nothing to do + } +} + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/SecurityManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/SecurityManager.java new file mode 100644 index 000000000..5098e4eab --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/SecurityManager.java @@ -0,0 +1,254 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; +import org.wso2.carbon.certificate.mgt.core.util.ConfigurationUtil; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.exception.VirtualFireAlarmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + + +public class SecurityManager { + private static final Log log = LogFactory.getLog(SecurityManager.class); + + private static PrivateKey serverPrivateKey; + private static final String SIGNATURE_ALG = "SHA1withRSA"; + private static final String CIPHER_PADDING = "RSA/ECB/PKCS1Padding"; + + private SecurityManager() { + + } + + public void initVerificationManager() { + serverPrivateKey = retrievePrivateKey(ConfigurationUtil.CA_CERT_ALIAS, + ConfigurationUtil.KEYSTORE_CA_CERT_PRIV_PASSWORD); + } + + public static PrivateKey retrievePrivateKey(String alias, String password){ + PrivateKey privateKey = null; + InputStream inputStream = null; + KeyStore keyStore; + + try { + keyStore = KeyStore.getInstance(ConfigurationUtil.getConfigEntry(ConfigurationUtil.CERTIFICATE_KEYSTORE)); + inputStream = new FileInputStream(ConfigurationUtil.getConfigEntry( + ConfigurationUtil.PATH_CERTIFICATE_KEYSTORE)); + + keyStore.load(inputStream, ConfigurationUtil.getConfigEntry(ConfigurationUtil.CERTIFICATE_KEYSTORE_PASSWORD) + .toCharArray()); + + privateKey = (PrivateKey) (keyStore.getKey(ConfigurationUtil.getConfigEntry(alias), + ConfigurationUtil.getConfigEntry(password).toCharArray())); + + } catch (KeyStoreException e) { + String errorMsg = "Could not load KeyStore of given type in [certificate-config.xml] file." ; + log.error(errorMsg, e); + } catch (FileNotFoundException e) { + String errorMsg = "KeyStore file could not be loaded from path given in [certificate-config.xml] file."; + log.error(errorMsg, e); + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found when loading KeyStore"; + log.error(errorMsg, e); + } catch (CertificateException e) { + String errorMsg = "CertificateException when loading KeyStore"; + log.error(errorMsg, e); + } catch (IOException e) { + String errorMsg = "Input output issue occurred when loading KeyStore"; + log.error(errorMsg, e); + } catch (KeystoreException e) { + String errorMsg = "An error occurred whilst trying load Configs for KeyStoreReader"; + log.error(errorMsg, e); + } catch (UnrecoverableKeyException e) { + String errorMsg = "Key is unrecoverable when retrieving CA private key"; + log.error(errorMsg, e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + log.error("Error closing KeyStore input stream", e); + } + } + + return privateKey; + } + + public static PrivateKey getServerPrivateKey() { + return serverPrivateKey; + } + + public static String encryptMessage(String message, Key encryptionKey) throws VirtualFireAlarmException { + Cipher encrypter; + byte[] cipherData; + + try { + encrypter = Cipher.getInstance(CIPHER_PADDING); + encrypter.init(Cipher.ENCRYPT_MODE, encryptionKey); + cipherData = encrypter.doFinal(message.getBytes(StandardCharsets.UTF_8)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + encryptionKey + "\n]\n"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } + + return Base64.encodeBase64String(cipherData); + } + + + public static String signMessage(String encryptedData, PrivateKey signatureKey) throws VirtualFireAlarmException { + + Signature signature; + String signedEncodedString; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initSign(signatureKey); + signature.update(Base64.decodeBase64(encryptedData)); + + byte[] signatureBytes = signature.sign(); + signedEncodedString = Base64.encodeBase64String(signatureBytes); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + signatureKey + "\n]\n"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } + + return signedEncodedString; + } + + + public static boolean verifySignature(String data, String signedData, PublicKey verificationKey) + throws VirtualFireAlarmException { + + Signature signature; + boolean verified; + + try { + signature = Signature.getInstance(SIGNATURE_ALG); + signature.initVerify(verificationKey); + signature.update(Base64.decodeBase64(data)); + + verified = signature.verify(Base64.decodeBase64(signedData)); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (SignatureException e) { + String errorMsg = "Signature exception occurred for Signature instance of [" + SIGNATURE_ALG + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for signatureKey \n[\n" + verificationKey + "\n]\n"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } + + return verified; + } + + + public static String decryptMessage(String encryptedMessage, Key decryptKey) throws VirtualFireAlarmException { + + Cipher decrypter; + String decryptedMessage; + + try { + + decrypter = Cipher.getInstance(CIPHER_PADDING); + decrypter.init(Cipher.DECRYPT_MODE, decryptKey); + decryptedMessage = new String(decrypter.doFinal(Base64.decodeBase64(encryptedMessage)), StandardCharsets.UTF_8); + + } catch (NoSuchAlgorithmException e) { + String errorMsg = "Algorithm not found exception occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (NoSuchPaddingException e) { + String errorMsg = "No Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (InvalidKeyException e) { + String errorMsg = "InvalidKey exception occurred for encryptionKey \n[\n" + decryptKey + "\n]\n"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (BadPaddingException e) { + String errorMsg = "Bad Padding error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } catch (IllegalBlockSizeException e) { + String errorMsg = "Illegal blockSize error occurred for Cipher instance of [" + CIPHER_PADDING + "]"; + log.error(errorMsg); + throw new VirtualFireAlarmException(errorMsg, e); + } + + return decryptedMessage; + } + + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/VirtualFireAlarmServiceUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/VirtualFireAlarmServiceUtils.java new file mode 100644 index 000000000..4126235b1 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/VirtualFireAlarmServiceUtils.java @@ -0,0 +1,366 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.json.JSONObject; +import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; +import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; +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.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.exception.VirtualFireAlarmException; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import javax.ws.rs.HttpMethod; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; + +/** + * + */ +public class VirtualFireAlarmServiceUtils { + private static final Log log = LogFactory.getLog(VirtualFireAlarmServiceUtils.class); + + private static final String TEMPERATURE_STREAM_DEFINITION = "org.wso2.iot.devices.temperature"; + private static final String JSON_MESSAGE_KEY = "Msg"; + private static final String JSON_SIGNATURE_KEY = "Sig"; + + /** + * + * @return + * @throws VirtualFireAlarmException + */ + public static CertificateManagementService getCertificateManagementService() throws VirtualFireAlarmException { + + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + CertificateManagementService certificateManagementService = (CertificateManagementService) + ctx.getOSGiService(CertificateManagementService.class, null); + + if (certificateManagementService == null) { + String msg = "EnrollmentService is not initialized"; + log.error(msg); + throw new VirtualFireAlarmException(msg); + } + + return certificateManagementService; + } + + + /** + * + * @param deviceHTTPEndpoint + * @param urlContext + * @param fireAndForgot + * @return + * @throws DeviceManagementException + */ + public static String sendCommandViaHTTP(final String deviceHTTPEndpoint, String urlContext, boolean fireAndForgot) + throws DeviceManagementException { + + String responseMsg = ""; + String urlString = VirtualFireAlarmConstants.URL_PREFIX + deviceHTTPEndpoint + urlContext; + + if (log.isDebugEnabled()) { + log.debug(urlString); + } + + if (!fireAndForgot) { + HttpURLConnection httpConnection = getHttpConnection(urlString); + + try { + httpConnection.setRequestMethod(HttpMethod.GET); + } catch (ProtocolException e) { + String errorMsg = + "Protocol specific error occurred when trying to set method to GET" + + " for:" + urlString; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + responseMsg = readResponseFromGetRequest(httpConnection); + + } else { + CloseableHttpAsyncClient httpclient = null; + try { + + httpclient = HttpAsyncClients.createDefault(); + httpclient.start(); + HttpGet request = new HttpGet(urlString); + final CountDownLatch latch = new CountDownLatch(1); + Future future = httpclient.execute( + request, new FutureCallback() { + @Override + public void completed(HttpResponse httpResponse) { + latch.countDown(); + } + + @Override + public void failed(Exception e) { + latch.countDown(); + } + + @Override + public void cancelled() { + latch.countDown(); + } + }); + + latch.await(); + + } catch (InterruptedException e) { + if (log.isDebugEnabled()) { + log.debug("Sync Interrupted"); + } + } finally { + try { + if (httpclient != null) { + httpclient.close(); + + } + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("Failed on close"); + } + } + } + } + + return responseMsg; + } + + /* --------------------------------------------------------------------------------------- + Utility methods relevant to creating and sending http requests + --------------------------------------------------------------------------------------- */ + + /* This methods creates and returns a http connection object */ + + /** + * + * @param urlString + * @return + * @throws DeviceManagementException + */ + public static HttpURLConnection getHttpConnection(String urlString) throws DeviceManagementException { + + URL connectionUrl = null; + HttpURLConnection httpConnection; + + try { + connectionUrl = new URL(urlString); + httpConnection = (HttpURLConnection) connectionUrl.openConnection(); + } catch (MalformedURLException e) { + String errorMsg = + "Error occured whilst trying to form HTTP-URL from string: " + urlString; + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } catch (IOException e) { + String errorMsg = "Error occured whilst trying to open a connection to: " + + connectionUrl.toString(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + return httpConnection; + } + + /* This methods reads and returns the response from the connection */ + + public static String readResponseFromGetRequest(HttpURLConnection httpConnection) + throws DeviceManagementException { + BufferedReader bufferedReader; + try { + bufferedReader = new BufferedReader(new InputStreamReader( + httpConnection.getInputStream())); + } catch (IOException e) { + String errorMsg = + "There is an issue with connecting the reader to the input stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + + String responseLine; + StringBuilder completeResponse = new StringBuilder(); + + try { + while ((responseLine = bufferedReader.readLine()) != null) { + completeResponse.append(responseLine); + } + } catch (IOException e) { + String errorMsg = + "Error occured whilst trying read from the connection stream at: " + + httpConnection.getURL(); + log.error(errorMsg); + throw new DeviceManagementException(errorMsg, e); + } + try { + bufferedReader.close(); + } catch (IOException e) { + log.error( + "Could not succesfully close the bufferedReader to the connection at: " + + httpConnection.getURL()); + } + + return completeResponse.toString(); + } + + public static boolean publishToDAS(String deviceId, float temperature) { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService( + DeviceAnalyticsService.class, null); + if (deviceAnalyticsService != null) { + String owner = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + Object metdaData[] = {owner, VirtualFireAlarmConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; + Object payloadData[] = {temperature}; + try { + deviceAnalyticsService.publishEvent(TEMPERATURE_STREAM_DEFINITION, "1.0.0", metdaData, new Object[0], + payloadData); + } catch (DataPublisherConfigurationException e) { + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + return true; + } + return false; + } + + /** + * + * @param message + * @param encryptionKey + * @param signatureKey + * @return + * @throws VirtualFireAlarmException + */ + public static String prepareSecurePayLoad(String message, Key encryptionKey, PrivateKey signatureKey) + throws VirtualFireAlarmException { + String encryptedMsg = SecurityManager.encryptMessage(message, encryptionKey); + String signedPayload = SecurityManager.signMessage(encryptedMsg, signatureKey); + + JSONObject jsonPayload = new JSONObject(); + jsonPayload.put(JSON_MESSAGE_KEY, encryptedMsg); + jsonPayload.put(JSON_SIGNATURE_KEY, signedPayload); + + return jsonPayload.toString(); + } + + /** + * + * @param message + * @param decryptionKey + * @param verifySignatureKey + * @return + * @throws VirtualFireAlarmException + */ + public static String extractMessageFromPayload(String message, Key decryptionKey, PublicKey verifySignatureKey) + throws VirtualFireAlarmException { + String actualMessage; + + JSONObject jsonPayload = new JSONObject(message); + Object encryptedMessage = jsonPayload.get(JSON_MESSAGE_KEY); + Object signedPayload = jsonPayload.get(JSON_SIGNATURE_KEY); + + if (encryptedMessage != null && signedPayload != null) { + if (SecurityManager.verifySignature( + encryptedMessage.toString(), signedPayload.toString(), verifySignatureKey)) { + actualMessage = SecurityManager.decryptMessage(encryptedMessage.toString(), decryptionKey); + } else { + String errorMsg = "The message was not signed by a valid client. Could not verify signature on payload"; + throw new VirtualFireAlarmException(errorMsg); + } + } else { + String errorMsg = "The received message is in an INVALID format. " + + "Need to be JSON - {\"Msg\":\"\", \"Sig\":\"\"}."; + throw new VirtualFireAlarmException(errorMsg); + } + + return actualMessage; + } + + /** + * + * @param deviceId + * @return + * @throws VirtualFireAlarmException + */ + public static PublicKey getDevicePublicKey(String deviceId) throws VirtualFireAlarmException { + PublicKey clientPublicKey; + String alias = ""; + + try { + alias += deviceId.hashCode(); + + CertificateManagementService certificateManagementService = + VirtualFireAlarmServiceUtils.getCertificateManagementService(); + X509Certificate clientCertificate = (X509Certificate) certificateManagementService.getCertificateByAlias( + alias); + clientPublicKey = clientCertificate.getPublicKey(); + + } catch (VirtualFireAlarmException e) { + String errorMsg = "Could not retrieve CertificateManagementService from the runtime."; + if(log.isDebugEnabled()){ + log.debug(errorMsg); + } + throw new VirtualFireAlarmException(errorMsg, e); + } catch (KeystoreException e) { + String errorMsg; + if (e.getMessage().contains("NULL_CERT")) { + errorMsg = "The Device-View page might have been accessed prior to the device being started."; + if(log.isDebugEnabled()){ + log.debug(errorMsg); + } + throw new VirtualFireAlarmException(errorMsg, e); + } else { + errorMsg = "An error occurred whilst trying to retrieve certificate for deviceId [" + deviceId + + "] with alias: [" + alias + "]"; + if(log.isDebugEnabled()){ + log.debug(errorMsg); + } + throw new VirtualFireAlarmException(errorMsg, e); + } + } + return clientPublicKey; + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/ContentType.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/ContentType.java new file mode 100644 index 000000000..879309c12 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/ContentType.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.scep; + +public class ContentType { + public static final String X_PKI_MESSAGE = "application/x-pki-message"; + public static final String X_X509_CA_CERT = "application/x-x509-ca-cert"; + public static final String X_X509_CA_RA_CERT = "application/x-x509-ca-ra-cert"; +} + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/SCEPOperation.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/SCEPOperation.java new file mode 100644 index 000000000..f9f8f0898 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/controller/service/impl/util/scep/SCEPOperation.java @@ -0,0 +1,39 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl.util.scep; + +public enum SCEPOperation { + GET_CA_CERT("GetCACert"), + GET_CA_CAPS("GetCACaps"), + PKI_OPERATION("PKIOperation"); + + private String value; + + private SCEPOperation(String value) { + this.setValue(value); + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..fdb49fd8a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..0689ffaf0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,65 @@ + + + WSO2 IoT Server + WSO2 IoT Server + + + 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 + /virtual_firealarm/{version} + + + managed-api-application + virtual_firealarm + + + managed-api-isSecured + true + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/pom.xml new file mode 100644 index 000000000..ed8eb5d9b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/pom.xml @@ -0,0 +1,271 @@ + + + + + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl + war + WSO2 Carbon - IoT Server VirtualFireAlarm API + WSO2 Carbon - Virtual FireAlarm Service Management API Implementation + http://wso2.org + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + commons-codec.wso2 + commons-codec + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-transports-http + provided + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + provided + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl + provided + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + provided + + + javax.ws.rs + jsr311-api + provided + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + 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.wso2 + commons-codec + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + provided + + + + org.igniterealtime.smack.wso2 + smack + provided + + + org.igniterealtime.smack.wso2 + smackx + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.jwt.client.extension + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.application.extension + provided + + + + + + + + maven-compiler-plugin + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + + virtual_firealarm_mgt + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/VirtualFireAlarmManagerService.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/VirtualFireAlarmManagerService.java new file mode 100644 index 000000000..50f1c1c19 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/VirtualFireAlarmManagerService.java @@ -0,0 +1,312 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl; + +import org.apache.commons.io.FileUtils; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey; +import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; +import org.wso2.carbon.context.PrivilegedCarbonContext; +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.controlqueue.xmpp.XmppAccount; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppConfig; +import org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient; +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 org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl.util.APIUtil; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClient; +import org.wso2.carbon.device.mgt.jwt.client.extension.JWTClientManager; +import org.wso2.carbon.device.mgt.jwt.client.extension.dto.AccessTokenInfo; +import org.wso2.carbon.device.mgt.jwt.client.extension.exception.JWTClientException; +import org.wso2.carbon.user.api.UserStoreException; +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; + +public class VirtualFireAlarmManagerService { + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + private static final String KEY_TYPE = "PRODUCTION"; + private static ApiApplicationKey apiApplicationKey; + + + @Path("manager/device/register") + @POST + public boolean register(@QueryParam("deviceId") String deviceId, + @QueryParam("name") String name) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE); + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return false; + } + 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(VirtualFireAlarmConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(APIUtil.getAuthenticatedUser()); + device.setEnrolmentInfo(enrolmentInfo); + 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()); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, + @Context HttpServletResponse response) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE); + 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()); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @PUT + public boolean updateDevice(@PathParam("device_id") String deviceId, + @QueryParam("name") String name, + @Context HttpServletResponse response) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE); + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(VirtualFireAlarmConstants.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) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/device/{device_id}") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Device getDevice(@PathParam("device_id") String deviceId) { + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(VirtualFireAlarmConstants.DEVICE_TYPE); + return APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @Path("manager/devices") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Device[] getFirealarmDevices() { + try { + List userDevices = + APIUtil.getDeviceManagementService().getDevicesOfUser(APIUtil.getAuthenticatedUser()); + ArrayList userDevicesforFirealarm = new ArrayList<>(); + for (Device device : userDevices) { + if (device.getType().equals(VirtualFireAlarmConstants.DEVICE_TYPE) && + device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.ACTIVE)) { + userDevicesforFirealarm.add(device); + } + } + return userDevicesforFirealarm.toArray(new Device[]{}); + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + return null; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @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 (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException 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(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + @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); + Response.ResponseBuilder rb = Response.ok(zipFile.getDeviceId()); + return rb.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 (JWTClientException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (APIManagerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (UserStoreException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType) + throws DeviceManagementException, APIManagerException, JWTClientException, DeviceControllerException, + UserStoreException { + //create new device id + String deviceId = shortUUID(); + if (apiApplicationKey == null) { + String applicationUsername = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm().getRealmConfiguration() + .getAdminUserName(); + APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); + String[] tags = {VirtualFireAlarmConstants.DEVICE_TYPE}; + apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( + VirtualFireAlarmConstants.DEVICE_TYPE, tags, KEY_TYPE, applicationUsername, true); + } + JWTClient jwtClient = JWTClientManager.getInstance().getJWTClient(); + String scopes = "device_type_" + VirtualFireAlarmConstants.DEVICE_TYPE + " device_" + deviceId; + AccessTokenInfo accessTokenInfo = jwtClient.getAccessToken(apiApplicationKey.getConsumerKey(), + apiApplicationKey.getConsumerSecret(), owner, scopes); + String accessToken = accessTokenInfo.getAccess_token(); + String refreshToken = accessTokenInfo.getRefresh_token(); + //adding registering data + XmppAccount newXmppAccount = new XmppAccount(); + newXmppAccount.setAccountName(owner + "_" + deviceId); + newXmppAccount.setUsername(deviceId); + newXmppAccount.setPassword(accessToken); + newXmppAccount.setEmail(deviceId + "@" + APIUtil.getTenantDomainOftheUser()); + XmppServerClient xmppServerClient = new XmppServerClient(); + xmppServerClient.initControlQueue(); + boolean status; + if (XmppConfig.getInstance().isEnabled()) { + status = xmppServerClient.createXMPPAccount(newXmppAccount); + if (!status) { + String msg = + "XMPP Account was not created for device - " + deviceId + " of owner - " + owner + + ".XMPP might have been disabled in org.wso2.carbon.device.mgt.iot" + + ".common.config.server.configs"; + throw new DeviceManagementException(msg); + } + } + 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.getTenantDomainOftheUser(), sketchType, deviceId, + deviceName, accessToken, refreshToken); + zipFile.setDeviceId(deviceId); + return zipFile; + } + + 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); + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/util/APIUtil.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/util/APIUtil.java new file mode 100644 index 000000000..dca274402 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/manager/service/impl/util/APIUtil.java @@ -0,0 +1,55 @@ +package org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; +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 { + + private static Log log = LogFactory.getLog(APIUtil.class); + + 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 getTenantDomainOftheUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String tenantDomain = threadLocalCarbonContext.getTenantDomain(); + return tenantDomain; + } + + 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static APIManagementProviderService getAPIManagementProviderService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + APIManagementProviderService apiManagementProviderService = + (APIManagementProviderService) ctx.getOSGiService(APIManagementProviderService.class, null); + if (apiManagementProviderService == null) { + String msg = "API management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return apiManagementProviderService; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..fa4461919 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,33 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..532cd8e97 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/web.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..0b6b913db --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,65 @@ + + + WSO2 IoT Server + WSO2 IoT Server + + + 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 + /virtual_firealarm/{version} + + + managed-api-application + virtual_firealarm + + + managed-api-isSecured + true + + + + + + + + + + + + + + + diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/pom.xml new file mode 100644 index 000000000..0090fcc36 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/pom.xml @@ -0,0 +1,124 @@ + + + + + + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl + bundle + WSO2 Carbon - IoT Server VirtualFireAlarm Management Plugin + WSO2 Carbon - Virtual FireAlarm Management/Control Plugin Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + IoT Server Virtual Firealarm Impl Bundle + org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*;resolution:=optional, + javax.naming;resolution:=optional, + javax.sql;resolution:=optional, + javax.xml.bind.annotation.*;resolution:=optional, + javax.xml.parsers;resolution:=optional, + javax.net;resolution:=optional, + javax.net.ssl;resolution:=optional, + org.w3c.dom;resolution:=optional, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.common, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + org.wso2.carbon.device.mgt.extensions.feature.mgt.*, + org.wso2.carbon.utils.* + + + !org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal, + org.wso2.carbon.device.mgt.iot.virtualfirealarm.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 + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.utils + + + \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/constants/VirtualFireAlarmConstants.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/constants/VirtualFireAlarmConstants.java new file mode 100644 index 000000000..3b8b5e2a8 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/constants/VirtualFireAlarmConstants.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants; + +public class VirtualFireAlarmConstants { + public final static String DEVICE_TYPE = "virtual_firealarm"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "VIRTUAL_FIREALARM_DEVICE_ID"; + public final static String STATE_ON = "ON"; + public final static String STATE_OFF = "OFF"; + + public static final String URL_PREFIX = "http://"; + public static final String BULB_CONTEXT = "/BULB/"; + public static final String HUMIDITY_CONTEXT = "/HUMIDITY/"; + public static final String TEMPERATURE_CONTEXT = "/TEMPERATURE/"; + + public static final String SENSOR_TEMP = "temperature"; + //sensor events sumerized table name for temperature + public static final String TEMPERATURE_EVENT_TABLE = "DEVICE_TEMPERATURE_SUMMARY"; + public static final String SENSOR_HUMIDITY = "humidity"; + //sensor events summerized table name for humidity + public static final String HUMIDITY_EVENT_TABLE = "DEVICE_HUMIDITY_SUMMARY"; + public static final String DATA_SOURCE_NAME = "jdbc/VirtualFireAlarmDM_DB"; +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/exception/VirtualFirealarmDeviceMgtPluginException.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/exception/VirtualFirealarmDeviceMgtPluginException.java new file mode 100644 index 000000000..150745ac8 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/exception/VirtualFirealarmDeviceMgtPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception; + + +public class VirtualFirealarmDeviceMgtPluginException extends Exception{ + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public VirtualFirealarmDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public VirtualFirealarmDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public VirtualFirealarmDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public VirtualFirealarmDeviceMgtPluginException() { + super(); + } + + public VirtualFirealarmDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManager.java new file mode 100644 index 000000000..a90c15359 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManager.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.dao.VirtualFireAlarmDAO; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.feature.VirtualFirealarmFeatureManager; +import java.util.List; + + +/** + * This represents the FireAlarm implementation of DeviceManagerService. + */ +public class VirtualFireAlarmManager implements DeviceManager { + + private static final VirtualFireAlarmDAO virtualFireAlarmDAO = new VirtualFireAlarmDAO(); + private static final Log log = LogFactory.getLog(VirtualFireAlarmManager.class); + private FeatureManager virtualFirealarmFeatureManager = new VirtualFirealarmFeatureManager(); + + @Override + public FeatureManager getFeatureManager() { + return virtualFirealarmFeatureManager; + } + + @Override + public boolean saveConfiguration(TenantConfiguration tenantConfiguration) + throws DeviceManagementException { + return false; + } + + @Override + public TenantConfiguration getConfiguration() throws DeviceManagementException { + return null; + } + + @Override + public boolean enrollDevice(Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new Virtual Firealarm device : " + device.getDeviceIdentifier()); + } + VirtualFireAlarmDAO.beginTransaction(); + status = virtualFireAlarmDAO.getDeviceDAO().addDevice(device); + VirtualFireAlarmDAO.commitTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + try { + VirtualFireAlarmDAO.rollbackTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the Virtual Firealarm 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 Virtual Firealarm device enrollment data"); + } + VirtualFireAlarmDAO.beginTransaction(); + status = virtualFireAlarmDAO.getDeviceDAO().updateDevice(device); + VirtualFireAlarmDAO.commitTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + try { + VirtualFireAlarmDAO.rollbackTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException 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 Virtual Firealarm 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 Virtual Firealarm device : " + deviceId); + } + VirtualFireAlarmDAO.beginTransaction(); + status = virtualFireAlarmDAO.getDeviceDAO().deleteDevice(deviceId.getId()); + VirtualFireAlarmDAO.commitTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + try { + VirtualFireAlarmDAO.rollbackTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException 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 Virtual Firealarm 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 Virtual Firealarm device : " + deviceId.getId()); + } + Device device = virtualFireAlarmDAO.getDeviceDAO().getDevice(deviceId.getId()); + if (device != null) { + isEnrolled = true; + } + } catch (VirtualFirealarmDeviceMgtPluginException e) { + String msg = "Error while checking the enrollment status of Virtual Firealarm 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 Virtual Firealarm device : " + deviceId.getId()); + } + device = virtualFireAlarmDAO.getDeviceDAO().getDevice(deviceId.getId()); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + String msg = "Error while fetching the Virtual Firealarm 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 Virtual Firealarm device : " + deviceIdentifier); + } + VirtualFireAlarmDAO.beginTransaction(); + status = virtualFireAlarmDAO.getDeviceDAO().updateDevice(device); + VirtualFireAlarmDAO.commitTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + try { + VirtualFireAlarmDAO.rollbackTransaction(); + } catch (VirtualFirealarmDeviceMgtPluginException 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 Virtual Firealarm 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 Virtual Firealarm devices"); + } + devices = virtualFireAlarmDAO.getDeviceDAO().getAllDevices(); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + String msg = "Error while fetching all Virtual Firealarm devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManagerService.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManagerService.java new file mode 100644 index 000000000..68c8ec94f --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/VirtualFireAlarmManagerService.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl; + +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 org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; + +import java.util.List; + +public class VirtualFireAlarmManagerService implements DeviceManagementService{ + private DeviceManager deviceManager; + @Override + public String getType() { + return VirtualFireAlarmConstants.DEVICE_TYPE; + } + + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public void init() throws DeviceManagementException { + this.deviceManager=new VirtualFireAlarmManager(); + } + + @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/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/VirtualFireAlarmDAO.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/VirtualFireAlarmDAO.java new file mode 100644 index 000000000..8064c524e --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/VirtualFireAlarmDAO.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.dao.impl.VirtualFireAlarmDeviceDAOImpl; +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 VirtualFireAlarmDAO { + + private static final Log log = LogFactory.getLog(VirtualFireAlarmDAO.class); + static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal(); + + public VirtualFireAlarmDAO() { + initFireAlarmDAO(); + } + + public static void initFireAlarmDAO() { + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(VirtualFireAlarmConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + VirtualFireAlarmConstants.DATA_SOURCE_NAME); + } + } + + public VirtualFireAlarmDeviceDAOImpl getDeviceDAO() { + return new VirtualFireAlarmDeviceDAOImpl(); + } + + public static void beginTransaction() throws VirtualFirealarmDeviceMgtPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new VirtualFirealarmDeviceMgtPluginException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws VirtualFirealarmDeviceMgtPluginException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new VirtualFirealarmDeviceMgtPluginException("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws VirtualFirealarmDeviceMgtPluginException { + 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 VirtualFirealarmDeviceMgtPluginException("Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws VirtualFirealarmDeviceMgtPluginException { + + 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 VirtualFirealarmDeviceMgtPluginException { + 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 VirtualFirealarmDeviceMgtPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/impl/VirtualFireAlarmDeviceDAOImpl.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/impl/VirtualFireAlarmDeviceDAOImpl.java new file mode 100644 index 000000000..c4896b0ab --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/dao/impl/VirtualFireAlarmDeviceDAOImpl.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.dao.VirtualFireAlarmDAO; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util.VirtualFireAlarmUtils; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implements CRUD for virtual firealarm Devices. + */ +public class VirtualFireAlarmDeviceDAOImpl { + + private static final Log log = LogFactory.getLog(VirtualFireAlarmDeviceDAOImpl.class); + + public Device getDevice(String deviceId) throws VirtualFirealarmDeviceMgtPluginException { + Connection conn = null; + PreparedStatement stmt = null; + Device device = null; + ResultSet resultSet = null; + try { + conn = VirtualFireAlarmDAO.getConnection(); + String selectDBQuery = + "SELECT VIRTUAL_FIREALARM_DEVICE_ID, DEVICE_NAME" + + " FROM VIRTUAL_FIREALARM_DEVICE WHERE VIRTUAL_FIREALARM_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, deviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + device = new Device(); + device.setName(resultSet.getString(VirtualFireAlarmConstants.DEVICE_PLUGIN_DEVICE_NAME)); + if (log.isDebugEnabled()) { + log.debug("Virtual Firealarm device " + deviceId + " data has been fetched from " + + "Virtual Firealarm database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Virtual Firealarm device : '" + deviceId + "'"; + log.error(msg, e); + throw new VirtualFirealarmDeviceMgtPluginException(msg, e); + } finally { + VirtualFireAlarmUtils.cleanupResources(stmt, resultSet); + VirtualFireAlarmDAO.closeConnection(); + } + + return device; + } + + public boolean addDevice(Device device) throws VirtualFirealarmDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = VirtualFireAlarmDAO.getConnection(); + String createDBQuery = + "INSERT INTO VIRTUAL_FIREALARM_DEVICE(VIRTUAL_FIREALARM_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, device.getDeviceIdentifier()); + stmt.setString(2, device.getName()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Virtual Firealarm device " + device.getDeviceIdentifier() + " data has been" + + " added to the Virtual Firealarm database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Virtual Firealarm device '" + + device.getDeviceIdentifier() + "' to the Virtual Firealarm db."; + log.error(msg, e); + throw new VirtualFirealarmDeviceMgtPluginException(msg, e); + } finally { + VirtualFireAlarmUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device device) throws VirtualFirealarmDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = VirtualFireAlarmDAO.getConnection(); + String updateDBQuery = + "UPDATE VIRTUAL_FIREALARM_DEVICE SET DEVICE_NAME = ? WHERE VIRTUAL_FIREALARM_DEVICE_ID = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, device.getName()); + stmt.setString(2, device.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Virtualm Firealarm device " + device.getDeviceIdentifier() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Virtual Firealarm device '" + + device.getDeviceIdentifier() + "' data."; + log.error(msg, e); + throw new VirtualFirealarmDeviceMgtPluginException(msg, e); + } finally { + VirtualFireAlarmUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteDevice(String iotDeviceId) throws VirtualFirealarmDeviceMgtPluginException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = VirtualFireAlarmDAO.getConnection(); + String deleteDBQuery = "DELETE FROM VIRTUAL_FIREALARM_DEVICE WHERE VIRTUAL_FIREALARM_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, iotDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Virtual Firealarm device " + iotDeviceId + " data has deleted" + + " from the Virtual Firealarm database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Virtual Firealarm device " + iotDeviceId; + log.error(msg, e); + throw new VirtualFirealarmDeviceMgtPluginException(msg, e); + } finally { + VirtualFireAlarmUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws VirtualFirealarmDeviceMgtPluginException { + Connection conn; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device device; + List devices = new ArrayList<>(); + try { + conn = VirtualFireAlarmDAO.getConnection(); + String selectDBQuery = + "SELECT VIRTUAL_FIREALARM_DEVICE_ID, DEVICE_NAME FROM VIRTUAL_FIREALARM_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + device = new Device(); + device.setDeviceIdentifier(resultSet.getString(VirtualFireAlarmConstants.DEVICE_PLUGIN_DEVICE_ID)); + device.setName(resultSet.getString(VirtualFireAlarmConstants.DEVICE_PLUGIN_DEVICE_NAME)); + devices.add(device); + } + if (log.isDebugEnabled()) { + log.debug("All Virtual Firealarm device details have fetched from Firealarm database."); + } + return devices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Virtual Firealarm device data'"; + log.error(msg, e); + throw new VirtualFirealarmDeviceMgtPluginException(msg, e); + } finally { + VirtualFireAlarmUtils.cleanupResources(stmt, resultSet); + VirtualFireAlarmDAO.closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/feature/VirtualFirealarmFeatureManager.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/feature/VirtualFirealarmFeatureManager.java new file mode 100644 index 000000000..7290b6179 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/feature/VirtualFirealarmFeatureManager.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.feature; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; + +import java.util.List; + +public class VirtualFirealarmFeatureManager implements FeatureManager{ + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + return false; + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + return false; + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeature(VirtualFireAlarmConstants.DEVICE_TYPE, name); + } + + @Override + public List getFeatures() throws DeviceManagementException { + GenericFeatureManager genericFeatureManager = GenericFeatureManager.getInstance(); + return genericFeatureManager.getFeatures(VirtualFireAlarmConstants.DEVICE_TYPE); + } + + @Override + public boolean removeFeature(String name) throws DeviceManagementException { + return false; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + return false; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/DeviceSchemaInitializer.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/DeviceSchemaInitializer.java new file mode 100644 index 000000000..450014502 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/DeviceSchemaInitializer.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * Provides methods for initializing the database script. + */ +public class DeviceSchemaInitializer extends DatabaseCreator{ + + private static final Log log = LogFactory.getLog(DeviceSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + + File.separator + "cdm" + File.separator + "plugins" + File.separator; + + public DeviceSchemaInitializer(DataSource dataSource) { + super(dataSource); + } + + @Override + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptName); + } + return setupSQLScriptBaseLocation.replaceFirst("DBTYPE", databaseType) + scriptName; + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/VirtualFireAlarmUtils.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/VirtualFireAlarmUtils.java new file mode 100644 index 000000000..216b41f24 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/impl/util/VirtualFireAlarmUtils.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.constants.VirtualFireAlarmConstants; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +/** + * Contains utility methods used by FireAlarm plugin. + */ +public class VirtualFireAlarmUtils { + + private static Log log = LogFactory.getLog(VirtualFireAlarmUtils.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); + } + + /** + * Creates the device management schema. + */ + public static void setupDeviceManagementSchema() throws VirtualFirealarmDeviceMgtPluginException { + try { + Context ctx = new InitialContext(); + DataSource dataSource = (DataSource) ctx.lookup(VirtualFireAlarmConstants.DATA_SOURCE_NAME); + DeviceSchemaInitializer initializer = + new DeviceSchemaInitializer(dataSource); + log.info("Initializing device management repository database schema"); + initializer.createRegistryDatabase(); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + VirtualFireAlarmConstants.DATA_SOURCE_NAME); + } catch (Exception e) { + throw new VirtualFirealarmDeviceMgtPluginException("Error occurred while initializing Iot Device " + + "Management database schema", e); + } + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/internal/VirtualFirealarmManagementServiceComponent.java b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/internal/VirtualFirealarmManagementServiceComponent.java new file mode 100644 index 000000000..bdc3d3a75 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/virtualfirealarm/plugin/internal/VirtualFirealarmManagementServiceComponent.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.exception.VirtualFirealarmDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.VirtualFireAlarmManagerService; +import org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl.util.VirtualFireAlarmUtils; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.internal + * .VirtualFirealarmManagementServiceComponent" + * immediate="true" + */ +public class VirtualFirealarmManagementServiceComponent { + + private static final Log log = LogFactory.getLog(VirtualFirealarmManagementServiceComponent.class); + private ServiceRegistration firealarmServiceRegRef; + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating Virtual Firealarm Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + firealarmServiceRegRef = bundleContext.registerService(DeviceManagementService.class.getName(), + new VirtualFireAlarmManagerService(), null); + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug("-Dsetup is enabled. Iot Device management repository schema initialization is about " + + "to begin"); + } + try { + VirtualFireAlarmUtils.setupDeviceManagementSchema(); + } catch (VirtualFirealarmDeviceMgtPluginException e) { + log.error("Exception occurred while initializing device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug("Virtual Firealarm Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Virtual Firealarm Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Virtual Firealarm Device Management Service Component"); + } + try { + if (firealarmServiceRegRef != null) { + firealarmServiceRegRef.unregister(); + } + if (log.isDebugEnabled()) { + log.debug("Virtual Firealarm Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Virtual Firealarm Device Management bundle", e); + } + } +} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/pom.xml new file mode 100644 index 000000000..77cd6f2f7 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + virtual-fire-alarm-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui + WSO2 Carbon - IoT Server Virtual Firealarm UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/assembly/src.xml b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.hbs b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.hbs new file mode 100644 index 000000000..c6d599d8e --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.hbs @@ -0,0 +1,105 @@ +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "device-thumbnail"}} + +{{/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}} +
      + +
      +
      Policies
      +
      + +
      +
      + No policies found +
      +
      +
      +
      + + + + + Add device specific policy +
      +
      +
      Operations Log
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      +
      +{{/zone}} + +{{#zone "bottomJs"}} + +{{/zone}} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.js b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.js new file mode 100644 index 000000000..dbec07bd6 --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.js @@ -0,0 +1,35 @@ +/* + * 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"); + + 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") { + return {"device": device}; + } else { + response.sendError(404, "Device Id " + deviceId + " of type " + deviceType + " cannot be found!"); + exit(); + } + } +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.json b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/public/images/firealarm-icon.png b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.device-view/public/images/firealarm-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7c5808697e193b734c127fdf563f335ecd094bea GIT binary patch literal 28584 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

      Xbds!OMAZOyVX815vlcvCahpl6FV`n*q* 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

      r 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�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

      !IRVBX%L5p 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

      L-yz73Lyvs@BzC_&rR?ZRhZnU}0 zPD4^G;RHiSWyw6>*R1yAe_o&6ctxnGD09={9~`!T1vBuR_93FAgxJ)<7gj@~U^(*~ z0a{?^1enACTrc61CtJ(x9!n}pG)S&^q#2tVXeV~}kit+Q+WKt_#I6WmnO(o=?5V0C zzajlo)4S@IV|qPnbnc)YT#5n-2l7)f)UZs>=|>9PrFm_R^ZBD{K2wzqrH9#@tqMuu zdtY;l{m8c`W%1WxNifGHa8$<3X5-vlkvi!T%8O8x^8qPG=F zc)WDX?VZz!;`Lr)z7AMvXvC)iRU`4<6|WfULw>}NT0u$H{K4dEQny2UfVldBw)HsH zVC>y?SaP2rft3t{4zu8&*DjjF0DY)>swEW z6es7HV|;9y25b7Sb)`RbG+s$CH}--1DO|pI+IZ(ul$R_3Ftmd83BJviG=_6nT<&0a zbO@JpD0M4kPtvp5q`vH4n0MM|SL>%c8&zmRbpiWVRWFf$nLU=|#NT+b;A?8sq8pnJ zn(Hs=lhEIpZlHT(b8yhsyL@+fKQC+li*jvU=etUVakcL85|6X(GuoqWcSh}xJ2~i& zo*K|!w(xfUGuKpViRAEbvFUkF!JljAj4}Er0K)bmSJX&VJCJ)4Tm%@`v0NIcMB(|u z#hGLVy)G+b!-4Sp6#2885pjm54^7$g91pM`Q{aZ(Y;1t9{D_udm8^-ULE)Iz))37P zH1SoG6mhYV;Y0Ke%h}J1Ik|^<`FpDcXTOQ(484h!qdFWcKB1N>rd|}f z2Nf@c`R`SJ%+2}3Lw{g$ zwS^e|TA#jt5qft3{}oDF=v(nTTk$t)twooq02a;tjqS_8?81Ta>&^M>kac7>`)*vY zFYiVmrKZZ9;>+>wg^h;a^3K*59+S1J!@hhlLkn(wY}CM&d-G_Db+n40lCJoCw@Ur@ z7Aca+^yzHZsgY9}L4iWGzCvR>Ki6zM7u%0J|2ucy+3VA_twzaYp^oe0$*qsu{NnTU z?e??ValB)Cd=a^QHr&o4|If+5%0%I~Z4~PZQj`MryN8{>D(;DpRCYRQ>N@r?OyQNG zhxc=%!uExSPJ6f1d_1S~HTR0qg!N$+4;M~O?vZPxnNSC+Ol88g8Q6do^mhKgp*Sf)F5qYDB{x(YC1=^yq8Tuxv8n-#SyoI?sw@E5I?eH6@{_8#E8hibM^47M&#;u!I(kFkM@|Y4H=qlzaF?aP; z4_&V(w8ZG255p_LuYI&6qs)yZ!!I%9bnfi|ITi&;66-hcfM3gY5yYD$yj}=8+m@;H zHDm{|VM974mYNewK4D?78x%^+j*9&V!7Enx4#60N9lA1--32Dzt0zJEiwUnT;+{SwEw(S0|<-|+?QEYedwck7+v(W?QU-ebfCVwNmWt)=!(SM$j*PPjPR0&>=VZCM4G0AuCFA&Ede! zAG%l3DgV6x5-YpxVJg67QcynEAY5On4lXA1P{CzEQwHn8TBN1<$B=S;BM!k>w+s*Z z%Bs)N5N&s$tx!QovEjTp6{iM4%{WlTu(zJQZ{ji*N1uF) zJ?M0})?SCEac}YI1m9EYm-*E;UGs3A`JnPcQ6HBGD7*K(R8pcIKf|pa`0@vp_0;oO zYs!v`SmwSiaUIZ(0@ff4wpm)0TXh-!sHSWZ$HFTZ|4}%azMvZS3_0Prg458E^E@3( zANsM_W9ZSQukz9{_B%HeO}^f`z$+2-rnMojNc(90N)BA7{GcSJEsLg!I~ zZ?o+GvT7KWFt<9a82tCC&CDecG5FjmEQ?eRo`i%$0C?mIGH(5}?$H)4qSP&CpLe=0 zf=z^`C-b0UC5Iy%#_l@G!_#(19ik7uy<`7of^6w$7JsLx`{p&b`|4ZT&Hwy15*mJ+W-~!A@xpqE|KhVj0}~KRo5A(P@RH_dWZetSc?3a{0!s z|NbPnmk_zsq5@k(CJ`e*SUQb}@5cTam;XO%X$-LmFIDdYDoyT@~b7abdJ;(JB6%8104=?0b=bq()4DVGvj4o+A1IZoZ3cEjd` zx(^I?INI5at$xB~m5NvKLhT*lrD=s@U8_y@#KWI>@?PY%!{hG0dj_BQ8Wjbkc111k zYuM0qrOgf0V_E#JAU!ME=AxK?OLW#(fkPyMz>DHeGlE0<4YC`m=DH`!x}+HP}6%VE@li6lbgH`cZm`gJix zoV4?7r!^q35=6>#O&{Wuw{H$`ZQ0>m@0rQc0KcNp<&4B-i$ReYwk&KUWv{ z_<>gCO<9+_=eGK841P`d`IvL>|L1$BZ0o zxZCB>-HGeY*v{E7J|IoDx(EoK#3zs`P89z zn->Fhd|(&_@2B|hZ4Oc2>~OY80z1P|_*hzHRpz#GOOB`9rL7Bog6*Gi{_iL2*W*_0 zwwIIY!cQ{P(SKP-;^k=)FH5`Z&B+bLWP7F?h$nfI-%Jn(3;MNB<{BF-uFHHPn1`#Y zsD!_Io3Ov7`>XJFiM&m?X)ii}KGy&EOUdiOs6bKa$`B1>`i|s7?HdKAcKr)*!0oV* zdZA=YxQET57{pSRofA*QJV~+&@F_HjH9pY!=3Y2l1Na*>8|W6iS8=%l%Dh8hJ)i~P zkH-86@61YKQHnfNZ?%-{0$kpl?KMQ&mT#q z4_!_AEGFVBbV`T&rpLN}UNMfd*N-J=vGsfc>Tt?Rm9Z-~y82j9-m`*v6ScX6KK zQ;Ju5z2x>iag2=|m>szv(-Fj7_HXY`=2NPeDhnjAfV4KZ!)$XHDKKlZejml#V}%ug zs;u9+#Mx3pfm1T1D}t(rwfMf2m2uE28JbP-2$nOcYylJvmtDiYHvC9UtBY0j$=CxmA&yfs?%VUuC^h@kR6S zH^@|XRK+N)5D4qjMSPJzQEZ~^ve1iC6NuDj_%Zq(D?@)8E*x!r(;(WqGop!o&^g8C zhze6RRKaua(jz>@;u2k<GA_-!k2w+xN+aoRJ=@p*PANhJZB!nj$V;eiVkhbzs%=aFwcJ*sekBO znL4qNu95M|GtG5b&NiA)18sSIHm$%En~yh_#DB6NHR{DvC66u? zHy@X3nRkreu?|^z>9iqtp;gh*1Db%OGP zR2?Z>LBGOF+EEgI;pe)&qPw3E_U|hX3YSk(ytnCxVvyE13XLr-JT`#t$6pg&TNZJC z^{UZHxA1r!+rz1wtum{Z7S2ajBn#HMf%4xJ%1PjL$Vz;LXIOa|cpc-h|4)@&ev*$s z_smt_r<6(p$TNaAi`Vm=5~C2dLRDX`t0!J1do&Fttnl()9f^DGt?O!h7W_Cy)h$cOHMqUTzM@Zw3;;^=y;{DTxSE0a4cnK*8BD5da*1)F|-`udS64Zp?GU zRcr5jCP&M56-pTzl)cqCzB&mGY87=_#Do33h}d^-@ChQrknKLVjqvjt9OU@n27)+= zt7pCNnX{{`W#ICOg^M-gf@h*VOWIEAJc^;V zVGXUABXJ(#1hb0I>8dN*osRXKxuw-}^IGKV~9Y-dyBoMv2dTy=_%fB$<9Y+ZllxpIHY$T<7OaZBdygaC?YEOjW>>CIyc}+|gX(#s zC_nO}TrJ(qdhg=uz=%tk*|#<-E%-ayxGZ8Zd_Uh+96{eF%ziiepdBn~HB~>}hbpN@(yvBQ>HtY10Ji>}cKc9|5!vH5VtNbSt!IeD6 zNx>XPjyi#A|6!%z?D%h13IYsFh?pONGRNAm-h#%d@#jd-gL`VD(H(vk?ypQ~8fFVA z>qNr%)!bsc&Ci+`)C4_T!;SJ z&=mh$fsZU>!qLCzYXFpm;p=6Dpme(pv-w`APx|> z5D#j7cn#*37@!tC&r2drgosXT`I%z!C%i0yUc=L`IVs-e{JN|{Rg$V4{M94{`O}1&%E{jchYyza~vEHGv~4f zUI%zM(#&ZiFo7Q(0`VAAw9xdKcbe?>Aq6e+=jYSrNJQK%jN8cxbGOi|&rR&?BAWjj z`r|O_cdszF-*OKwoPXy(Y(Bx8eO-rCO8@d~ z$o?c}`~zOXWz~PFZuJlD(7_6$LG;igvQ;v=rICMtHVnXnu%)Ghf+V}s`8~@3` z&6sB6BEZTQ1%&d#(2McC7m)hSrF#!d&EeZC;@4SsE+0?#W|7!6Rh>Ux@Hd_&Y6=2&|HazL1WzK>Vx@k5 z)hq;t~m#G_EHo2@bFahlkFXW9t<;hZXMXr_iK%y)Lp(SQ}^w)JMnq z_f{UG?xSf8veo=fvE$S5NaU@i8?pE*3ATzTY&aY?1@xk#_G2Ec~ zL{h=wScyPW^347dG>t2(DTal1)}VpA3SclwTdFUuYfv`*+wnjfb>Bd)1K`iR6wcoH ze?V^VA?N{2JaVUOqEI@0-|oeTCHpQaQ_aAcG4-*xCiYXk%$V;(9S<5j^xCwV%FEPjyWiT*tL47cF(5nKY<1U3}6L#IuC#EWp7##@xZ$*C&y^Z!G*1v zBW?>)Mt`Np=IFK{DF4z|w?niLMEiYib>DGr!GC#gi3l3RO$*;NIYoDby!&Vpv(3tt zZ{?eUtdCrioOwMqTRCgOUgCMYui(^iB{!`zX?Eod03|Yt2jKLkUFjdV4}Q+KKw4R*?C$TQ(_vytRmTRyX%~J-tO# z!1aXV#`urXT6(#j%`pQSTki4l^P`PF&}R5O3;p8jWHk!k~)+IvSu8bTovV)4GTT zm}W3IxSb@`@0NpR&m_Z3LH%|Yth^y5Qz3a{=`5xH>2=hkewcdyNt?exIa=?nF1PnK zD(}{a(tk$wUWLcFRa3=oT}7M>h$EWjBP*6`2sI(&)k>JPTku*NY#uTvD^` zPTUpGJ_=PDJ5472qJry^p<*ttQv$1sLvhQ88{Zlfyg%U`@eXe~<>H)Jn( z9k$1FFNdT5wk|i{qt}8&bPhzW{+F}37N`-8@UXiAuzJ}fdA9v|-gL^$;p5UD90#RG zK1y!gm2O&gdDHe>+hd-ycYfDAlIR^GXsH2vJ4Rffcjo67O)Cp&(w^v@`oZCIT;a#- zUp*447d+N8xF+dteDm(s2PL6pWnHoZQ!-ge3HVuP(FbfJq=YOG8a?9tA z9dF17eZ@QdaL7n4dyCI#MRUVfS?Mh$4nn2%3-XwEH8M@m! zzixf(Q;KN8tbyi@835Lphu;K&`Nl}(6#>tzEDUo^IT7K2O+z8 zy_C*RERjArdsz(3IhZYWd`&rHCmGlS^Bl^~@zONR8 zQDTuIbI}JWkoA>kR$#>VHpxMu)ETzC+gzM8VO*JHe9Y4RaHR6EposMAmYC!t%QfF$ z=99jVEE=cZ!c^w5)51yQ%6ZaotSfXN!F`PVR8qp*=6fF-D@F_h&TZYXJ!bmug|?0< zy_pey@z=AFQ(1|BpF$N4{NOlA%ITgjl#w0ZGyNPjmi4rj=6p>v)1%pZNDZ82^KvWZ zvsI|BY|fDf#ld!)lc&ufklQ;T;sF(}izOkkIG&#$fTAD(jD>3{cRnJHn3{L(O|Hj> zZ9VlhMHA`5raCiU%2SO7Vv>hB4xV$P8$_?Olq^27B%2D=oi(ea%|sG!Oegf?@7Tzj zq|Yadrd`SXaU=Zhy^~apCj;?84;md#A_Bb}>}T*)B`|CZ#fyF`o|k8qu*b=`ayYh9 zRAbkgJde{XMcBRR0;?8)1`GuTB`3**C24DZFDyL0Ben%n@0T$3ww-XDApg){;K92U8D!!h-1DRZ)z=@|Bv}WK;U_`?VA+`!N$yaxvWbp_wLJyn8=_fd@ay= z@aSvu)78{{nxbj#`cvL)d*c86+7@7NrTT=@(a|gDgP?V+}kM*WFijwSMaQ)xNc2W;5B4au+K;6MJE8g(R>VI?=! zGkZ;9wlUeFtK5la0slgdSA}o4w;G_5enLZ(-H#l2-K_4b^qz>=<$YD-mz2YU*}h$c z$->WuWC$EU{m5&owSm9MZn1mw&y}yn`Tk(jftcaTWeXM*#{{QUb9;wZp8@njr3f&oFtP;A zUU4~kI$cb`1Zg)7$Bl_^pWge}yW6>FU}&cc<b{Z{~V9u|NRF7o`7S#_L8L0*MbM z_q7W}U|o98YWx0hrmw_wQEu`!>UfDmd-W{sGjnqGNw>E@Pebg&qC7`nOX5{@&G{UR z<5BaH#lxUa>HX=s5d5%H@+{mM%Zcf!z&((SZE)|YK&hQIv9W%=$ZeQ6h}-L+O)OkZ@w#!;YR2dA zfVi(a=K+v_Nl#>TmSPi@88(&H z_fW;;@9JGXdzjW^G1E8DHJv-@X89mytB4@Ch=_4^4LX9ZUwKZ=qY^wO=pBw)~JLs=0W+=3J(xir7G}Pu4+M|^66BG3} z48{kg(~EA2Dh(~*RGJ-i2%#Ph2>DP{G^&0kuDw3}I70&?>Wnek2;DR|czN)boJDzH z)fJf`RHQT1x%9CAKrNPuA*eqzz8b$Z@rmP^@t#PLMg0?Fj&l5%5zzha_Bz%|jrOdT zLM}nb*rxbG&29FhX?0EYOoTzSMKOJ>Fl$UWH(vAH-K+EZufmW9_mUOJjyE20X22~i z(1<|R&XMdXHl>SOcYHDZ)D2GB!Mx;p>ZAM54eNm;7}t=~#f~tM)8$@ksf}rF4ObU$ zdVKaLvvKVwZ3ohTeEHvod2l|P;3T`kyx`&T;E86zXO3MfPthVZ6Cev9p+7Xm#*p;I zyVNhmp3<;7qj^LyCw^?&!DYg8G~8MB=G7OR9?3!CqSV3b)8C&M43`@yjQV_SD^qMb z4~rn_Sa0E+KX@|ESTXs>BgQ#losWX<24>0(LCa|^X6lj~n$M)2H1ucta*tuHmvLY6 z?_N?e+`4;tNdho}c)a+@G?3eNs^dGh%N?sI_0Z)N6u49TVW-!PKRPnM?vhSYadV23 z48P0$?&2|D=Wp!)kQcoQ_oDfqG{|GlS6stICu%OL0qE+auN{-e^80hO!j*8z@n3mt zT!)w+Pl>-C_Ncvif0};ArB*5Z$S#A)R*jpRr{rM(0yBepcP(qny&F9e?8a=0*EL37 z+J%obNoz6_zIVCo6iQ=9mwij*8k8}j1!Vx55s9tp+Xme|jHj!#ayFcz?bPMC-!vQ5 zd%!ZkDO{i_vA#dj_xHfV12cPX_pBb6kg203?tl6OxpYE77%gj_d{+XVfDNFw!zTN|@>AUUY)l#)}(Yj@}4nPo)Ekh6$6j{oY zEdpT#f)c`BYLz+w*&_@Q*(0(IAw)$%Mu@T^D<~rf0Rlw!$hrTt&-=dTI?r{yxcb!U zll=d`d9Uy1&R%F&8{XzF14bS2TX=aP=BUz17~bKFhBAfh{pl}UvYU1(J-+`>*!=$$3YqzcuCzo3FJ#d- z)Euw}M&&(|8x}Cgg@n3-!8Ph&rzdy8ljR#S=KI5nGHHO^KSGUAQM3yV_}yVm>wJyi?Vq;rm{Q&DqoiS%9(u@tnRGIGN@a&pERTyf%(o zl;qxxwY!dT<9bkN3;Vn}l$**9$h+;F=$g)exFG`R`Nu!h+`i>&=C2!9;6^u5=iE)T zzWyOg`XhDF!dO4_rrv{LyJw@X#Y5*x+~{o$>Q~koP>@pNGnIm*v;u$m8huz1U0|n5 zFz~mvEip{azh5SBxhkXcO%oyS_K1Z=LSeG-`rSi@l(%79tw8ek9W>V<;WdZQ;d$8G zNI@#U5(dFTLx|4f$@b?_uWk0%tK9J;G=#5?5+hGP*)F|BNC=6OSWl&;e0p?zRbJ(W zwd?dgH)8!RoBw(q`o-DQcQ=^w5mPbe?@H$*!N;!H?BwrQ5hnl%^U_y@TG zL>v%zyzk2VTy9Drr*9|U!IR-4CTG`*`uiLB?h?mSPxoE_l9z8|H?a`{pka`%0(HP0 ze;M+*em5$bIR&Zf*QVN^?)#uQ%9{}v+dS}@HnX}tz7K1Hsme3(*Bpg-g=sn^w+|Yq zAx6He>^nRRH9d)3z-)DDDvLjIBzjP3ZCS?Ww%$d%rH8da8O<5Bg>dqV?RL5Li#tUB z5LN7j%s>9KtT#g!=b_c^<}eq&jhe$dTOlQZ7XwA&TVBH2=RMg{CjZ6mQ*^L#%8{eb zUR=9=phP|(`o-TO(*G@vuJ#yEF-Z3UG=!};on~+P3epR9;Kl5%afDKTy!_>z5YRzu}3H_5h=ps>S=Q1hvP z2Q-c3rXTV$V4(uG`V}CCvYWsrEj8@kj`!((6nCt}=u=UlF+qAzBXgA3$VHwHoWNDM z3jF@=lnQwKw{lG#2SXmWNgHTBY5WXQuQzh*r_lUsg9_PP0Ux$OKq>qF-TrXe_n zsRoS*oV$j0X2T6m${|0iFA*b)Ki_?U6iUO5e$`Lt{!d>s<8@9}Iyb)F%T6|u z$w=^U9TmBAXz9P*=6(m@-PcD%H9mtR8UfRRM*eEdyEBs;fiTk74~#=m(q>}}MEIEz zH1`O~f+r&s8%n39HMUgU984p=Scxy6Gdk+zBV=^zrb&LZ&NA^{Z?r~U!reOLxa&%)xMvk;5XNDb?@H7wOPDn(5fkn z?FDB2r`F1w5W1jtAA*3>W+qzd;*87HrF0lSu3y;YdW5Q-U z=7Fj`&svHF+H)1(=~T$oBP}xLMs(87-nsDLf_)cl_r3EFc({H5fPGL{1s2Ph-6Y=F zZJM7vwnN`D_rB@691A;uUqF)kmwVGR89NErE_!3A_5m%WU^_NFWsvvY`N-j-6)Z#~R&tWzhA`|lg9s$|v&uyum))86X+)8}ODNYTr;NwX8{y;ou!`gXp%Qdu}=Lb-F@wj{5= zPV|69&P6M)mF+o*8x$iEN*}gX2N3JCuV6 z6G;(m;q%NHZDxI1r%ZM8=)7BAZS2P8p@NF?V~LK+(pERU3Lqd;~s?*UF;NU7n{qFsj;ZFF}FHB8&1< zUq__2FiIlfzQ>ZRZKbP)E^T-3n*C;5Oq&<#P^_T!RlWP;+Lt_+Z=L)FhIYoYU$Ei= zp?8+Yh$S!L=ReI)B$=`wIh~r@2PS$9%8r}hMwc!Knm)d#G9`v3Nf>Z1E3qjQnNcIC zN((#M1ZuF7NXj__EENcr8^8o(kk=v7VCvNJRG0=d>a?>UR=PV$ zxT>bR%A?DfP)L*)m9~oOP!jKf`q!9>AZy-Z`Aa{{<3gsQOT8bX(Wk>f8xv%jX)YfmJRdd7qkRG1;%mHY!^!rg(Q zLJRQO>@>fm5;=^PAhwV)Xx1siDt7LlP#MmdPJ3OyK4w54o4&lgpA{%N-NlDxXI#Dx zJz~uUc&nm^J1ya@`d!$-}*KR7<_i5c0&Z5UkQ?;CpaLxQ{HEA(h;QrdC83v>>N zKq7|>QskzArv$y$rYmss4MlC%wK-;_<1LnTe);himh2Zo*A2O?RRI*pmm)PK5SRHM zwbxhsS>KJe!RzHcwNv!|UuKR z6obTkT7SOM(!-xxid;w#X@-~y03IN13P)I=oIg}URP-kiKD&5(3P5KEsOg3v0aWCH zsuv1f2XeBgC}a33VflnUT&@Fdh-GoNhh?u@B?S0DDFNDjxH+H-7``7Ehj8mb`Q>K4 z=)e@)TLnG>YQq6=GQr5RE$ph%51p6~SQOzP&xOW&KpQ2fEPebUk3_9w6Zi;MvyTlf zntPP@>;=??R3eG@@M$TjX57FuO_pi{***Xi&DVg46XLliB?q6{5$GUiJpqs85a?wLBUYB0X(?+0T8$aQY2zzl?Q91{u@)O?c(_3yuB z@Xji`Gw=Hw!hep;P3A@6p(PBUJYZxH<(z*y45KgJsyKmGFILrj4g` z;5(4z0JC`G#&`8gP`E*AJSC?Tu$Td(JTOKLlEHp~8IqyaK4h;JM)ESx$*_!dH0=%JQ6UnGkAh4N`2x8|4Esh=lzjUmYnd z5wIw{i8m!3wXY&BCUpm@$r7EIO+!ON1-s7-R(A)T86K^{ES_~|UR0BAy;J487r*;& zHkX-sO3s$402A1@gHwsZ2g=osn)khl31iR_Q@YMC@=Iwvi@f2!-L|C=yY&K4+E z_`9>qHy8Y4w?4Y`LN$E2F_^>B&MFn>Q8a3Nk6kvyJ@qHFzJ5P8V~Nu{pjF8HJT(E0 zsX7M?TYXZ7<2?G5oWe@Y1UpFFq~M09xktw;-NZPyC8mu@i{iG8{ch?>yRV$sSIE4L z44-4{)_jwKRX!2=5XZk*x!-C>((W_3)_3pTrQq~}@WVI{Pr;6HZ%l!M9?Gn+%M|oqfgA>TV5h99@alw((oZoIgWSWh<|- zmp@zLit`1jejf(+BP&8OMCetwjHGSjk2d>q8YB*;Wst*Y>~?LWOk;&rm(1+$GxN}! z+!B{+Nr)Ujx6n{M*eN5D7|2S3ZQqA2X9Sck_5(11ffL-H!Al-1Ls_@h9TMg&`TMS& zdqkIECRLdUI!yF3RC0W|@R5EEAJDUxj+Kfh>SK~?x;uyX&nZ0-R?@Q}*}~w|D)9_) zs;YCwsbO$mqSNpnXkGd?=tx&6n;vXgQpEe;TDZ?p5wWE=U{9oP&0$b%1ozXNVyz&+ zn&33xErn*p`q{Y1KKJ#ge@eH+d9dsH0x>=$m4;M9WR3^Hz6qpt4IjNZaRiI$u%a(a zYp}XtB+YyEOrpEo=5w%ea^WX&w8kL?{h;7KLog_2 zSPyp?mfD`!d~#ncW5s%H>6O{`_big1{>_H|k&l*@**$HrESW@$+LEbahas#V;w&6# zUI;Qhbhu*ao1yoVDy8s&M55{0*^~M~!_xV^d*SdhWjBR^g*8nqa>_R<2Iw7Y!U{6q zqjGb*?q8i&DflBkmhE2<*8&&$l42w4NV$3$gP7byYZ>)gtgZa)Qk1-P)^2fHV|M-s zXKc1tBBb`wm~jxES~?9IBOeXZ)(5suw+xwuokh%&az7iAnV_+)zahrFF=@@h^BjzA ziVCV2{scxgj8UT)5_G2L6_`+tVL)QFa)>0*lBb?|cL+p|l{FRn36^&gla((&${2e; z_Q>CGsON}qAM*d)A{S0oxy4?9XN=uCtI{A4K3xIpM@eqEla%AK!Qjt#Xf2hpZA?-Y z$lzrr9U?dc(34<8u~)3wL>OdDF(=H*2780mU*wC|2O|&z>j)YvnmeI9rRe;7aQChy zu)eQVhZ<%th895*Y@cX|K`?1=9>cA$$K|6B(8u*p*<2f)3{P1d5v)9}yDYfc+4@5w zx-GBEC9lqC$B%BAYRe3kjj^@0b?vxy)ndxUAoU^~raLg*VdC+U47K%JWr^~88WmHm zPPc0O(fwc+_lbdQe{K5M&=|`8NJ)W1x0Qo!VWb7C#v+K3vg{tIgf5n8Bq+bHR^I4E zgTa@EFE(v_PwyTcL&0ztqxT|%j^10XqV$9o&cK#05#85P?knef7<=U(fozfBHhBbZ zGO+BtA%v1D!KK|H&l4G}r|@C01*!*;NeD#uz!F(fNLdOxgZ)x#PNpBFTV9mqWG?o% zwsxV)iEa`8#n>K3DR}_b;0L>`wmNd0+$})6&%nwVUv3<`7_@gW9ba6Tb3~(izT0=o zhh(+?Ju8X9$zou)V==^TJ}gWCS%JAkv{>tHEbdN%J=m>D#W`d39PMQkti`&|!!b!}Npg+dw#ue6Um_ObOA+%eNSwnY@3NSlUe%neCTtTv|de+B#d~ z*q3N3amq?8*od&ih!*UC;-=U0ZPZpitXe$=H_*D4HpIfhAfpFVOUHMhK0fGyuV6>p%=HLQhrZZE=>)WONsS0&Jx`Rn)X5TIXgCag7U z*HtVlahZc_s!xx+N@@8`Eg*>YIr6jSIh;%4!xauxUd&vXu{Kw2(Ec&w_xHSYR5ug=BXpvwJNNAv1ZG3}hG1!7CU+JaSA&_z4i~w#H zGUI^M9$bnT`~+p3-b*v~z?bx;(EC4n3W@!#v~KlJ(-;I`DJy$S2ch_V{d#k8YaEoL z1IbiXwU4aa&ryT&-sR=xX>@Y<9?o(t{B1B>!MXyX)=MDCL1NfjWq|ydJb(fCEkY0n z@dgk;Ah1WYE?K<^?uA8HYIDC{hCwb=0CbQu$w1{#Y|*g{dF62P=6R6FLu(Ysp#yLZ zX_^Y5xp(g_EV3b01@S>B2t{ZbLF$9SAF2J{Gp?L4Q}6^mD^xkekNJZk{g3K*fS=Pb zUUBb_?{$&>XB%)fkmV?GvyMTq6X_8As^KLjQ(6FJ3-nGBuPmU#z%YkWO`!O}zi)OG zcraaW#C&_EUd=lCYBquuguf9$W_aAXCG^|JF%BeakiM@{i5-)ZMer$5pbNF2l!;7D zj!?>CbFFBTV;PCc{I*kW5C#bB9N$_{+JbNyx?+OmQ4rpa7^d(%|8%En8Li2ttc16Y*1cst-ORiFgji0>=DmcG<)? zAvs|LB}Gl}TCOb#`B8E;QQh<=(am}L=ty{{i&nv9qi4+p2enej0T!CMSzg%%KDgz# z5laFkU2b4{H`ESb5V9tG+y@}I<)K?0g7Pbxcd2|D<^8~&_Y+NZ``;B_+S7t&n*Wn z-o2y)lvhyXz#RUAfh=U~*BMwJRNDg5k{W;eNMZ2&V9yRLW?mEXj#5HpC^h~pm(IK^ zBjCr^OsFcCX| zpusaUGpFyrW1e+tXyMdO2c04O9{NXzS{Ud|_C31fE381UPiX@60<38mSKx@dEA~;H zu+~vZQaag20}gka)a4A3V?a%!q9o8CN#H@y{gAAOG9A9jIsYP=joNEoXbKknbbWBnorIu z2HUYlL3@o1&N*CC_(v#YL4wPw)aA)c@?c&p@3BS<_x8?6=2>^4zx7Y-8*p&6v$Ing zqXxzR^RvmZhL@I-(zdC0Lq-sK5QEtoMMJ5NaQq<-3gBOipq#vXC$)^B(lDvPg!K@M zO#Ezjrwo(rA@sB2>hpZ_*3!1lN)!g)+um6TI%e3A!Zk{`%Y|J=(B>H=S!y(v`d>D% zxb^J-Ib5*#WyCAUHifwzyy}1{*sulB5y`wcCHkPy#p78*o~@4aISt&m zpeTB!NHua=MToWfC7)KbaGW?&zCP}5P!41RMTwe?&m_y#4EmQ?TJu2Qg)TEIGxBGT z12@}v;EYM3GUpVF<;5#5>fX&TdL~s+@uO5F;$cDdHvb2jl?A533q8)z$>L`929Tz@ zWZG**kvXtIyBT8pUztyzd_tE&He%|O$MleYI%E-Qu&;aEA*;t5NxOV7_lx$~mMo?9|2`Qn-J#5o!`m#Ji|^*i>1Z-jRm`90ATBubP~U ztpd{N#Z)BU(q|iw>{GXUFxH*DRUW=_Z)zK+Ccr?#Y{G>5TN%J>vN>%lOELJ821KKo_zRnQm?b_~tzAVhSya!Xhi}QxkGyqlLfc5sJ z=}>DWK(J?!>!l!I(X>o@ozJaIwDP8? z@x5KW0A)A=t0%Z$1G(1*JiwMbdgRFW^y)Dfh5JijHjn(B@2f9p46&Q}q$bIZGxe#7 z`1x%eAOEy%eAzKRO_ReFD|=2BJ3#UOvFPtiLr7(Y=+{QNRwJCe0TmHgs@Tp>UzA7V z)2w_4aPgIR1RBQ`1!XvI1v*;K;+5f^s_FX%cUH&;8V^ho1RJVPUG~KC8S}OQk=N1j zCCMY_kpXTohq6vw2X{Jz<#+)K8FOu=ByRrEO?v z=;D&Q+nv}JIOmb0T>BIlI#z`#!HmUqj5how%oI?xl|o^hisF-cTLg9iK-*V%3Xr+5 zCD<$*f&$ef0NW#9CgXpr&!<`wo7-VgsqS2+p)O5b)@1XQ!*>&r<;p6}DN#VT!gv*? zuwQn#KCsV2!giK!Yv2*7Ck@vqcPCSx96j9Ou3ERzF*rCF95swR3kNP%g7NZ0Dn3~y z$E+})LZMjU!PJ3ifWxMwH?%dysx~vyB13N2sk=0Iklk&I3T}h5jx0OYGF$0eZp#nu z82M?2VFN2^N!`WE7o?C-T{EB&MGJ>~zC}W%Td-7`fiKOYb+D<^4CPMsYoJkEEknt+ z>~upg0bOt3enpzTU1aBpqtD2ggr8;J@SJAfEGeiMG zJQz)IRr{XnmVY4I_^qd>XFBlK#3}4k8mfF?R;f`QRtn3Csq)x0gkNJ(9-T9bEr&DB zCPNO*V)nNNWmxQxp;xr3$*__|5~;Wth6)NAo7x}oSzKOPv967LQMl&o1 zHKEDr6{!wj9pNwtIQZ?6jw4-@=p3fCrDaWiqztuCPtaKGfLWUGeEP){CXUS7HLJh` z+;kc*l&+^4X~yH&_JeYjN`m}<#V$!Z#f zg=mU5!}b{j*12^UUXT^*b&)VWs6XGDg5cPOlc8kQ{?3Cv*iX`Q=K zdzwJsUqJ9BFH-uTZ-LkJ-{m!5ITBvyo5N)SvFlXNE*Hk7q73dBIhLRZv5xos)1k+ zxW$%h@&l=gcpQW;lWXcbD`)2|u>w=%wj%^IHRw#EJeF%%TV)N=33PBtwGM$uY3e+M z;>sv{rWD~hJIWUX>@wuo+4*RFPS+C79ZPtWzc>sNah9JFvJd`f?Afe}NP6<@;(Kdh zr9EL(A~k|vNnTx@5xhq(x7G4~zCx>ig}(=~&b8!(X3?X_MM+v@{8}CY~h6u@mma%Ts~z5ZpfD$q=C=WbiH!U-6+?O zPAQ>DI|`}y!{-CYt6Lm@`+0!5C+Adx|IAzYI8Si>`nxcQb^t{~iV)Dd9}hlk@J%oi;Gs3oa&G6l1|9iX zbMbBcAHUS_zJFlq)(_pP_Yry=~1)~DSoTrRY(cN}B zFGY^GB5A!*?MpPAaUNK99sfi7#kbbjpfeHrLydc|){iKnDD@{`Esc|MDBFgyS3RL8aQGKRO2Vym=oI;+9Y2B77a6`Bh}S-d7VLmOD@mT6 zNUNWPfzWI(n3Z+#WZqw{1Q+sl1{^!P;b@rjWmf7BXD`i)f#b*%PhKtY&+DG-gCV{@ z2iKdbElMbP$KTW-V9rEnJ9POa4_{^1D)9dPA*vqEMA}vk3j&Pa0VGatWB5(~6B_5HT!H+=^0%L_RRu!82p*=Zxjp>lSuRL^`lH93ow3iS`f#uhqLx zsDzXYPivrSByZ03zms{He&ymkr*)&JKH}UhV%)k4_ML-S-HY#k>`4L3zEPg@)eYjH zmE0r|O|U<~ensQM+XCSd`)af1=K$3WaJZh4Rgcm;g!gxC=yyb|of}W%MXBT0MbjbB zo8!B;5!<6C&o4ZN#K{~iJs}wEBqs&q4o3e4=AR>wMYp1U18jR+uR^ z(2nXw7R7IcTQ8E8Z)st)P8RfNC~Wv zu4!*ax*S99>|pyONuzz1JLFk7ldVxW`6=ne^WyAmuj-yKWhIzwCcI>Qj)kAv zT&>>*3C8ApfP2C|^9Y~`N z!D*~#E1js%lkBJOAp53M2HjOjMzTE#h=+SINEMb^1G>1z2O{z?Y}KktPdq7*34pu6 zCkdjN8~Zg3Z%FVAjg`#@tmk+ra{g4eg>UI@31eV!vB|T&vJgq6V*=Box6EXQHi7}r9lQ^-(Seh}>e>z#u zhZgNwseahb7wSO3={cInP!`a@B=Kb}zAlS~8i($&T1TT%iNim7xExA%Yt+X1{QUd9 zi{=|v5!}`ci?*^3~(X7(4* z3zX9E^KCoI)%OV#{9tt?X=i=*n2~Tb-Tofk;}=2dh6pcIu*?(v1hE}N3!1;d+UrsV zv8Q;V7ao~8WjR&`D|5|y-3QVjDWZ@~qK`rP0n(st`^)!MA{hQ2%!55_L+(Pa>8OK zitv4avKsnnEvhd65rOMJwXCroJi6mym%IEeoZcTTxUSlzX!VuLp%>|tbydFLg(tns z8C(r{?~$Y1(iS{m3jM>Bg*?0=A+Y=#l42R_u3_HnmZRSBBg10b{heImxWI)x0-K~v zR~UPP-b@b7df2l2PpgO1;VonH;hipDub4Pn3t3aQN;6ov=vH|D)*W3*bO;@gaZ~Un z#*~2quoJPbyZFj`B9~-}eS_aRn%0((yH>0{F~z1AKgcQAK567!HuBv_8phNfiX!MP z*oIC~C9!GF#q$rAaDVkd>IBO&gJebu?<}41osUxtMJA?#`|UE|7_>^m50pg89Q_nX zwckuz1(J|)gsmJRifgs391Xy=2B2FZgb$C097B7WCP_JFk2A80%;_nMBL)*msx}Uh z^h&GijY;s{%vX$+emHC@BPAeFpuYgwWA_opqorOC_C`5an+xNx4^fa1N|UKGsDuPx zZ6tA^a*i?ofWeXJxG@LM88~*4jVAbFs=5{Iv5{rAf>_Z-1IVLTbycEmoF{D@7$4!~ z1+gRrCK6mC@srIMfz~}A$@|H4fgxOL@pRhXV`f2n2d5d2=1b%l6O3Ptu_@S|dFDkn zc|Rn`Fu3CWA{l(cI|ysAA{Ot(!|hZ+lWqqu1)SbF7{^oDuwd<$2p$>-(s;wO~(LKRLFH>Z7= zgqxwP>=0L9mgT9^ggRoVPT&vw$?va)K`$MU&CKoOncL9-<+Igv%=h8YC1{}n^5ePH z%N2`+HDA8fW$sdBsNQI7_53(teNQ}NEz)OWl#*i;x)3TMs`MPP_`$C`?zId0uXqHnJXSA%O4ynqhX zWxRP6xi&_5aTgTrKH@Fce!`!Mcy|p6m;4J)kc5yg2zy=+vVR8*^-Zkx!>^x*0!w@% zdB?xkopNf|QPCPscp+xF?7K$)JVz+*vg=rn7#*D2Xf8W_%E-6GBEj{|@5L+UZXO3F zO{h$+!ww%-xMx~>W%9ODJF`F5`SU?-=EsYmWI<3tkbm0z6&7v~8cL~K=^}{#at~A9 z1__g34t}r`8cQ0ap3Q{5zBZH)o55AaqC9lPBLs~~^b)bTz~E6|`pN?#2RH7C-aZsPANzS2DxQ#;%=#cwvUTp-<6NIX+4 zHu7{F|!fXWi4LF{a|PE?aLG2`SPMmSAA3nK*Pv4?{uvkaarcskHoy?<)JnW>P|?+n=X86l62k37c+8W-#O_kU^2s8G_9L?bcmL226~CIYQOdJ zj`2@h4!p?`9wC#bTBmHYHuc)d!=A-Sx!sMv+Utk!dmGS~0_ zbn3J_?ed)P{M%jih`qcn?vB^8F0PA@+?aXaV381~lM8Ijy;I2oU8@lXMWNerqty>Xd z8Kl?9oHkXEf_Ht+x(q2p%xXYJXxPCp>MvG%6fo9M#(b)j^~%UW)tue8ytU`i(|cES zrar{HLm3-9?t7~Aj-!UK!+2YGgic=18y8-yYvUGDavLh2c*!Z__)MqPu-pem!=$6a zThJ3GhZGjO3&E8Tlg1lweEl`scamI~;nb7vu8}FW^I+WJgE*C#m(YlE^GxzU;B7*$ zn3D>KhU}fTO>)|f_@2^GbjT~GCfXv1q0B?-o_7zW9@1FJFC#^{`}16*IA%4l{*t|nxvwmGA&klByRZn(kOs(2hSVL(RPgb_%7 zI~xfj_gZ@Qo2rI1|0uv6$}7u0zfThB1WsKkF!lUj?)p+ z9+yf>M79FOiy*$^`3YoSaO`_e?5Sktj52q|yiA6U=GzT|01&yQyDMMHZT3DLgdk#| zUhf$QXRkQ-q>J_$f-*r%Qx~8$G0^%MX-5XFqBh&8*1zG|GV{ERpXr$wFdcVbJII_1 z-oNQCaYp4VNXXP)1Tcl^#)#kpja6Zf;Pv+L?@+}LDP`!2I-iEDk`y9h z)&)U+a`JV^*)zz201fKfXLCg8Pk?pX#2!!K6OLmO%TA~K;qE)HZJd!tc}Z)t>rUR4 zI6s|F^PXxby86UPGNG^~!p730>9G<|nd1jM@y5a!cR()fCml`IxLyEJNuG)^+c1oA zw8}V@(UO-$D@bZ_c}2-PzUn*vsV)ulWtr(-q#0|`JS^L0)yTGkMj{HW2XMl~_#OrO&{hQ+_pyeCOj#~o(638^Y9L2qXssg0- zBgtn9Y7v3W3awcX{L&{7dhFz>WD*K3Qlbwu2@4o|`FV9&*2XrAE1$`kaAp_E1lnj8 zpFX(bXziZc0+(T^6ovbLQIkdXS+g@EK2}e>eC+RDPB|i8A}Ud``rkUo3FIV8hvB;j z>GbwSPjQz{)1V=((FGw2E5k`tZccXFsoh-=GKFFTK(}j` zaDK>q>ZGIg0|z@$k-O>I9aktdAJ6A0NatSZdXiC~pdm@|MAP*>{-sRT=5G zl^9f>mZs;9Z08H>ZL07JOuy#kZB*IfT)FfOJ)trCxIK3Dh~ZZ$Xto6n)`3{JBLUGy zBrYdp>xo=6zO%`j7yffu@9GZU2y~F&`6?%@Oensfo3G~fatahM7xAjA6jp1j-7xoT zotTKQptee$R>F=e-Y#|QX`3TR>Sie2k)hh0wiqap>K@}hzQvt>Y_<`a{cHHkYte_A zaguSYn4D~}c0-18cIh|Gh^XBz+!CF0*tKU1Q|X=4O)@Fu=PiqB$nLL8+aJK{JX+}{ zsTJ+2h(IsD9od1*^~Z~mcaXW>ged-V)nC3l<`2yZtT;3v6v`&=zW+1yrTAnvHQ|qI zKB=7ibl?5`W$W(?2zQK*p4{GWKnFPsbInj+6+f1pR*t;LbM0%ivY0mL4LxAS%-w>j zAKEQ<6r``-i16g*Fu~MXF${@^?Tl%+OrgJ9)i82k7W4;YJT|O-Ir3>hSmJbJ^k{(5 z0g(0|+@@Jw0-(q$>N$H*xn4m;@7^o=+aglRVgutfepIA(c9-1A5nT|YaDSz)%`BQy zLTo|ABu2(k-06eu^vseiGkLq*OmT;t4?f7OT?^}f_vT@pw6a=0=(J5KKAKN*LkoJd z4PCeFbiWXUD1mQEe5sP8XRix}O+7jO_4vCx?h$+D$G=Yhx`+3`hk(@utVe*^VJSO$ zpKwr7MxC!^Mk=UO4ijARdv9#~)Dq+FJbJ73>czt?36Aq?=?6S#%GT@>6x+X^G^$uL zmDppOz!fYGvUw@C)3l`8wC=WPMk=L%O_@!vTOY1QpwGaOES6To>XC9A6cp6O2Zv|M zi|e5fM@IJL@l_wU=g*9@6?4TbU4`Cn1vJ-xyP-k$r1u3==rdXbYWuaduo#{!rQnFz z){kuA=o6s66o0<;dqbnrZm6#w@lW4GB&u~D!xiX)f;P*{UvpiQQt(ZB!!`c$pfSJ{ z@&mpdmkeGgd002I$6_zNY->;n{1*huaB6p4ANQ{^60hgVS$pNkk=Hv@a9Wy|V-Ea$ z7Yg778l%Vj5#;<=O(!m~!*XRwAJnLGs~N9Fh4+0$%{5P}9HX3hZs24KOrPtZQ;xgg zFu*LKg}t}}owgu-m_g$-{N(rJQnY3EQJlDLnT?@s$aw>m>P*l1o$KNPftnmoazXE? zT!HP{B_3L+%^~WpyQEts51^|Da5O<0{Hn=F!wBl&q2508+RgLOETcbu?(dJzMhMwK zwJ|*2V8#0Vpok@OZ!n~>)6vR zj&d5L5{9^vIQ|-Mu2lwiu~*R6u~^>A;#77`gw26s`B0fXDrO&IkrnvKuMJwx{RcnGz80*2^z)%aYVmM8xF4 zd4!NQ^3Tny_@66y%gtSYaA}y|1-4E+-{47#=TZ)#bidB>2ThAQLif9;_W~Z=CGmjJ z8Ap`l_xm0dj_Ab|6iVy>aM$!r$4O+dB?dqtd%L89b9$FM+*)nS-TY#<^1Skz`P+o@ zBVXKE{aMIroHp>{ZPr4m@)q{S7_<zf}P zT^$iA-#LM+l+bz}SWyBcU#*493>5s1O}f05}a6U-L%0r|b%s2sa6VDxE0qDJOc zvD=A2LlKFM{q4nX>*7t?ObI(QVdsnR1CGtR0@UghT_O4!WJct#rCt$u0Fl z6WOxAy~~=Uyb(po)7WF7Ya-fgu05Hw+K(O32~19{q+@7(Xz`e9(BS3 zI8iOqjJ2@xsgnu(VL4bg>9%~+6te?Am-&4essaTrl$wE?q(TiJ*vea;H()eBBgGsn${h`8o>VV-|0a)*E}g$N9>^E4!Pw-mtTF*GcrV8d1nO0> zJU-vmY1u=(cRr@my$UJ*f|e1$IloVU`P|Zl%{4ja>qflOKN8~PBOE`@HD z6r|64n^Bkf3v5?Rf(?Oy$Eh9}17aQ&{XtoQo=81@*VpL%I2Gj4ZET)do7F^)rRm)yhq7+XMc`Ln{=jPAN?t=~b0H8onH3Nn=v7{yZ1%g8Ycp_A{0YMKs9&g=j zxboxoXIEEJ`1soyf(}KCo5AXe9LhAUOJ0>-OA6zcoSnA67p34pe4(GcoF;nkT zh(+=~rNa?6W+4L}Bl|qR?_<9!3z&m?zx5wgrqr95eXA;cYbqN!37ha^I%X$yb9BNb zwLV|1PaH)_Uq2wlRoRX653r>yQ`zH}J%jTI!Lt^@>${vswaga;m4MY7~d#bYC zMY8V)`nY(%GK7=boGf_dI&Ezmh{m3&IeI+{-+kbpe=UpsKlDW3Q$}cev*PxO(|ty_ zTrND?_=c}*_7Z>sD>x}r%FVk{Gt55aHB(29zUu?#M2~wyxXs6bq3lU=#hS>QQ+J1;ib%@(-%Egen2^<$BS0fu79ls6nIA z@DS&Z9(mSy1(a>| zSHPV8-bH70vx7LQ0qbeTVDavJ=R!<=GIga&vc*f?bL5tCjE9b;>%I2A&g@*}hGM>K z_lieX*I1a1^!Oa<1b=G09bql~pd{Dk#dnUjblC;1>v?B(;+7j~H^xHOJ=VV$^ZsCm zPCZ#^NVNU*mTY`=Nl4#T2s`d*L=w4NiM@5nGk7U^qB!zc$BDn0Qk#0fXaDZp&5SX! zng6qe@%v!KOSTq}&q}mZ#R&++;w6igD{V{c48(I^4VVPpF-vnx-u|2)cuLSVhh83b z`TPw6xD-V%o@b4G-wP&iO=tpW<;R*neqqiC?i#53x0 z+b-xVJ4Y6B-%FHLe|>$kr=;J+z~ERuP+zV|=*9@pugfOKvAia?g3aU@nrqhGp35$< zNa=dhB%SZKwoS`kjAg3;&f>|-K4Nl2!^&M5d0x|T6ZAF@3!ZDh42JgATXuepK3HYt z);9R;-n9_>E0~?HMRyPBZ5uEMOT3LU7jb!cI#Ic)oA3`Yl zQ<3F`;i+sDKH+J4$s_xNUapwELA%$#Qx|^(hW;q1<76q}zD?{=z^9Eql&T{2e>&OS z|DkM(hOc#59xTMy^cVcvLY6MN#jR|g`QUDKLM!^TM9eX(#}~B967l4}fSrGh-1S*> zj4)2$=o0=8?aP0#gEyzq?wUFt6{FVh;kA<%-**X@#mMVmaaZ0bmiYUa>uAcYmwyin zZEi^9{6!p>%_|kTU;mxQH#R%1AZS1+G(Ocb8#A}6ouJ`|*<+w`Tsqbc!&f6uFd)C% zf;kUOY2qc!p>qd>r<=lna%bkMUHrkKC*(p?^eO)jZ>KZ-iR#%Ri%l(uJ5xzHh#3=26|doUA$u{TXySvRDaA`0_I&M0 z4HAG|fX@R3uD#Ws!k)5Wm)W&N115#?#bP_-zw^f=lFNCEzy^49_je~>p%{E~UdVb3 z_|8`9b=bOX{m~Fxd~#U2fI>m~Pyf^P39yh5=LD1A`}?Oqk-lA*cs_+&E5>%VmD)$} z@_uysbG-EThtZhUwsFIdnTH!6*c;IX!2t%lbWI;bpXjr29U1Zl+bH39j|7~{e6`@F zmYN0B+~Bp@|8!~LQnXo>vTUfB#AE0hn0n335kN(M>{Ku=_)gOBHx$kwzmz*n_%-464;CTZk-ISJL_GM$6GBl8R6|7~s^mWr#)=x$Ab;fL-@}&7e`RX!uu^83t*ks=vG3xr zlER$M9z*eSRmQvI5|M3^7GP>?|LiSnNF;t6{39VH+hUJki1vr$G|zFGudIJhQ=H0t z*}VW$pCfsn_sV03YoN~%L^6GOqM?LU50fCvPBpwq)O0P76USL~6F*04vRuh9SO zM0I@o$oH_7UCLV5FU2NawkCh>j2aBGqb#ouwign}S-SL`lPw9SFDH1U)D*1+WD{E~ zBW$J}g&=zZ8NKa0E#?nn#hG%zA8yWxg`cY;YRl=OG@PSF0`#XbE6jrWN=tI))#A+T ztNOb}3z&x`QtZUgKAE-saZITskEmmk+~A=ITX%qGG(Y}HD^L?V#=Sh zYNy-!8#vVS=)Ht1UXmLKWRKzFJXcp3bDr9ty*v+VJ$_%x`~SOfzhb;64njQ0_z3W2 z1W5Bd?UA`)>`q>?1kPda=sup;npGZHK_0&Yk>N^G5aWwW=|4`mjjd;Nem8LP5x6!! z#V+)js_lJ(wQBd?@g_^urMu$x#2!if%O z<<~85f)8uCSyNsDf%bqRKf>)=UN;=bpjWw{do$*w=XhEtf*=g(;@T>uC z?XV>ZB%8%WZSA$EE#`LK_i87SR+Qm}Z=O;v=n-DK>y}7E0?KRep1aeWpWRh0l6ZXx zqDNKGh7I~|AqZ^s&OcA?nID6up?U5iO<`(7hZ4jC<}0gz&_Y&u=XpsBsDM=c=ENFKd~y zidCiFnT2Fu`8GFrC;PMR0gJL1*NpN$xLwrnaAD+R@8# zK3n|aE@i^{+R3NT)AY3V0%dY!AT3e3sRAfNP5ej907aN!z%_yAYG(7_O1&G=Em2aq zX^In(jsgER06|(R@w{0$N4xclkiqo>K)XZJmtH;GvC~U1T+{zAYHR$DVm2i+bdH~^ zt>Hg*QLF40)mp$}VNRoLDxN82P@Vt8_4b`Yyi&W4-Np57&_fk)deDn6xih`#_o*ZN zosp$~j>`E~Js&??1z>vkdAQ{ z1SL68>0`NmaKYLqr@?&@s95+ML^XPI6buyq2H=cj ze&O~rpdXJkbCQdb*?4CQcz?ReQ%Z~jzM~pG)%M~jgy_$O&34`&KSIt5+`+mX`dN|u zc3<|f)Rx*{jkcq2&MO}dH|Y{tpQDKUUAH1M{XJEjq3(LynbJiMM)tUP^hVd;(`N4_ zkoTs53Fn}2=%5ynk};dvB3y)9^TH}8ztCtow`uw0-@vxy3m-*`(rvSTZHb#0Jq`mq zaZR#J;_fQy)b0}hd;b4{;yq`esQTyYM^;$w(~{w+Ha#^b@gfD6r<#@+`{jnym3;tY1$JIMDQ$1jyZ13zz63t8rfZckV3*GD7$snb15VUCc zx?ZpQhgr+LsZxSaEv_aABBdo}>9kVHOplz)&WjvxzRzC{jKmMHPcC>a1%07S!X;I0 z7J%sSpSz+4hTj2l=7IN$63ETUmizDKcO7vfAYi%5(_deTo@eWl*DSHRR_fMkU>Zkv z^1wi4+qHdKfbvT`ZS~S8VY1*PL1E`cAl^q}PFTVdyhxfYK8~~<>NusRR8PJOOBEq7 z%U%bl7R-&))he|FP+$YKx<_7X!af!HG!5J$f`(2FKx}je7 zbuBwTXtJzyzzC~KefF4*F+Tq#G5?*l>rL1>_S06Q!hLKv<@3_{sZC$`R zvKq?9_iuc@U?czi>7NWL>(=`7M=Q=8uk?~v8IxrmGS6rgIe5d z*6-GT1x9FrDXkYPx4pw2t$?h{G$FAU_(f2_D?9NBaCy2GE(L~Yeh0ICzv!A+ z?!0v@;CFj|i}BpxvCreL@$`M063tuu5J7GkrU&tQkq z^Mj>u)~sHb2X~yei+9AT*ge(IcykkATQBFaeJq!K^WuvTp?4VLvTw zInV&Rg8Nk6Qs)YIcb9p`c`_R6Vm`m$25WK~_Q7thuY594b)_SX-U`R5!*(}_5^v)0 z#p)S1u-PvMyMF8Rr`Ftvm#ME7;%qI{?i(2CbG5hfJ7x6vX+t`~2uon3!wMTmNApyE zGjLq5#cm$m4T;BAwd_QSm-~i-ZQ6JMEwW_|PyTvKP`~f0OSuZutqNU|qnaGlcuZWZs!^_`9_<`4Cf2knt>hnCEm-M_y zy>v1cHbP{ZfHRZAMI+*rvknr!w5T*+%^E$0e#LRN9)Y^B;e}CQusF zXNx6H`~B`(4eO<~4cWw>MFm#_s?ZqBoJdZ;-=2R$-9*>VyE{+VZiwVIT!wIO7+KS0!Wnoc0=%p3zrA7G1Fj2n3Q=pM5?$C}q#33r@=|M{-rc|1P%%ISo8T|U8- z$&HG0Ld+O!e;@|H&Lq z&;Wi?AHu5gs&OK=jZlN?Aa zdx*wrC8kZ5v{KYx*Cro&CB#8aAQ}_oI735DN=jM}u}vRdb6-6=BPaOIrl{b_cK7XV zTUkJ-?i(b3-34pi)Bj-1t5?(g^2q4C)yyvodV0fbxxe$ePP-P&n41&wlhZH#!>(8@6&lw zJrVWX4F%oQMJeTkc^NpHQXlBr6}F{M9K^|?eez46&`*87NIqlW`s>HAe_lN$;nN<0 z(f7k3aGitYrMq3fkr8$ITwRsn!nb6rbbTLv5Q%5)9iv5r_w3-W+wZ5YsC*_V6Ajd- zN1QugXEXi6&$rs^g1H|1M{l)>4U4u-p3=RrVpsnBc6@5W)=V;3_sc_cf8mZ&;nonJ z8dEsa?eJ-$gaG2i+lLPn6cmuyHDghg#Q{qG7^U4`iATlfXL`t&#PJzoKe~zrMI)8V0fm|B0p)&u0fV*c^5VSKM)XHtU?}1%Q^eREKe=&r>s1`#FdL7 z04F%b7PM_)kC0RFte42)o7@5MGtaoA}zX zJ~F667&kj&al(C|$(Z;;-}D~My`@j4cz++4&+~td3!EMY^FJ?F+T3OF z$Bx%wu-~!j5W1s+*a`tdxEwV^?0pFy7|8vu5x?8z!-o&QR&<%=xgDH-nKh}CDS{ih zQ=9*>n8b*=r`hc89FWFO z1!KFed?!Ja*_pPWprG857EC>50*`X^B7HbbLLSv-BznS}+%5Ay@qy#ax>ey(Ji<3> z+Fs_P?+G0y*+&3U<>j}T=QtA;9c`Pfh3Na{!PQctF?nZ=We>_}2 zTIJ2mZxJYaM^Uesy|R`W3{2F48deF`fq&;r58HUfb%|cCdF7#mSlb4YV=Aib))mHk zkEwQT%rLict7hk%HoUwfg=+^e6K>jm-_!;x|JWSN&KT2&M=jV`Q<6b1<`jm2SVK`keB{p=+f=l^Lk!xf}QSGVU{ey-x9=P0N;x6*C5k^O!pCz^{h^p%zK3mitJ9l55-9(VTlUYTQv{a&*UL$F zvY2#qyh4%@>PG`Ra5|-eOifNP8&J43sK86@?>RHyyuxeR7`EcGG25Vjm095Zf?iO0 zb3_H9lQrGO(Hz6~F_*@8d{O%$Bg1=>2HKau^xPhj^vE3lI#Dht7IA}tU69{xFd%iw zTeMRdD*U zh)PU@YXoewP|YwInB+Bh$1i*;EN|?m=iwui2Xj5cbHn6AZ`-zkb0qVc>BwTM*<46b zswuei?P-Dgs%@rR@Lb=OS=h>>U(B^%W;R{t+pYs;9ThcotA`0u1UOK51xJK|v2os* zoy-2JHc?pEhB7!-0o(M223}pr^S(~W80liD`Tpr;#3?rNd=YUbsF~fMkm;(n#JkNc zRKeZ;&Lr{tygPf@*>7ucBP;EralaHf#A=3Ok;Phi_g%MWqgO~!L*a3i^LgB2A@49T zzI?dTbW3*AAqKuBKWcg=Jqx2;E$P=4eXV|#6aADH zUS8v|CAwKZ;+^c$*Dd`vixXajc;#?IBI7D7?g^7NNn90?@6krUMY|!77&?ohhD=12Pz#)=MUlr4U7FYN89V+tK&JUy zG{(t*+4U->S~1-wcJWwDRVllx4=DtEl!*C^Fz81HhDH<;wqbB_xLs6e!p>yhIHh!Ne+LKj^nh^(lZvn`nZv`gX0Yw^;0t-wMW|{{2pqSXDKAgSo)Yvx z>Iv8V<{d%CmwCpcxArbuQAgU<_Z%yyMWKd?PxJCV2wiuxUQqPm_{-OVckRENt>c~l zURJi^vOB`#JF1_L7prQGFRfD)iPke~7b;E`+k%^_LUxLgPO*;v3kH2DBO4dNyZ$k; z!P)fEx;4j!R76(qP=jAKcD)f#8_ASfKvK-}OY(rrqDkdsh*-yedBnhUc@Ap{Gk3_S z8(}5-&YJRR0%b8J9P_!%FC3hzee@l^VR2u&!e{y3NZUp<$Be(f>Eg>+wY5aIlhjjQBi;z~c z>e+e5H{Q&rz;WF>Xh0{kl&(=DqoXR)}nUAd!=%Uu4dUydPUVLT?R%E8t4s&5Yc z1`lJ70IsR+Vct`YSF#FLO2dV%@?BIt*8VTqo^UKzeWyLXdN0C~x8G!03%foedDNb| z7CJOTU{b2TW!c}b-SL8R`2=|*X7@qP2?-+9Vw3U;7*#c-=WWYf%e#>cjTrf#15k)}rsx3R0Vcdtw(gjo|GV(%7|!;JX`!CN&X+NtoRQG`p@MRiGM;m-$me37Ap1p zM^O|c)99?fqa{tdAK1E zyg9uHbEs#SO1ml=Om=aR%lhq&I4ZA>#ti-ocK%2_hKv|w%Os(E^Nky4HU+>yR($e!dX?)R z|yMXr2F=uYysi>-^}PH3$$+VWwzqKxYC(C&yj zbn(VUdiw9l`KBYALb98te(|eF6?kEG8|KH2ayE9Rn6gq-HHv4OR5fNmIllwB`ti5* z!`=)T&Kdu!irNejf4Ow#SKP zRqp!BVJ|%3!(n*OkQTFg*Zl3uq_m(XWGAyXIHXQn&t5x*9*kI8z}Qq;uL2=A*vENB zA@JTgDX9)|-@vTP)dY^_NJ$;43+oB0SBZp(yA{4N6IUU-kMyK3@ZJgkR3|*d6CHawr~2lTak{$3sy#Z@BWz)PU(!c@y<%O=0k6)>YE+36)$DU?Q-+Uy1`qcIA*< z&7eF)Ct9*`_-0DgqiU+I8cqh$5E*d|)Om*c%HSF}{MsKbbl|bT(&QCxg;EBCyld6Z zd9f(ykM$#5LVt%7fNu9*6%YCCDW z+%$TW5Wx8C(i?dfx{*y!7rIa&;l4~t{e9CS`b))ayiCjMBG5g)I>VYs8Q~xi0V3J* z?+WD=xmTXXhdv_!_GOzbr8#LQfPSaMLH`DwjWdNEypCiEvR8^~t>k9@IO_z7YIUJA z(PwV2M$DkfkE3O*c4?t+H@*A)<`FL!bXyAEk;dQ9Aqxgk;bW~(XjX3=!j}r_hX<)? z>F+zNLV7W_aYp}Yc^&u@PTdx5eZD(2gBVoNebdCCk`Onz@@SXY%XTx=46-$dwRspa z3kF6*kZD?9NiYl`)yvhR=f1^m*5!>&;hCA_4Za$ikT$Kch*bN=mvdp^v}uh?ZmY}^ zt~kz%1Rm)sW;`+WHtdp0OE=mJ`~Gy761YnUBj)-cwhI@ZywalXd_opo8z2XAMv&|= zA7KraZkWxV%ix?}@frWPWJ@+AeS}9_=9jul42>~qIXvpw6c>Gl$}Hf-1mu7q3Ho7J zBYI-;sz~I!YKZQz+%4!TlHn1F`$XQ2@0=~(y^WiiIG%?&2Ux4eulQ|n) zl{%uEUtrdzBJ1V{Uoc3%yL%3n??jx?2_^#92(mF{-QmYDm~S(M!v77y{B3mLo%$w7 z;)yt&z6R=YAkdK6;hUZ{%4F}~575|>+W{VjP(GJqST>CC6L#AAwE8)>NRW(paMpv_ z;YENou#@Ce_T^CribMrH@?2{kuX6mew$2U9xzT5_@iQK)z|tUM1|W4221z5$p~|~^ zgenONcUamFq{FY+IXC{umpQ>z><+te%izEes#e^Og<7mZ5DPPLp3v>DIo|OfYverN zFrHw#LvqjE$`j3Zl-PO)HrgkJ0hV3m8Jryxi+ng*Paoef^D56hmA7(#Q|9GTa7*st z^q%o?5H9`@ZW}!yMJ6l~woYqM6P>{aIWyA#X2%@~9Fstz?+>a|SSm;=Su{N8*wAws zZO?Lo!y4ti)|k~0r;zV^g`D&O5#g~IW?+-r{^-x%EV}z5daumV6BUuhjsKYUyg5z}_#!7UCqT^_xZ9&nUpE36Qk@nWt8o zqoq=NhX^|TC}zL7)s+-G?hI_V^z899<8`%B(Q@D7wtubv%D(FL`^RfN5-^j9dcu~I zV6B~P%&Co7qt}b8eIJXh^Nf+sxOJOjFDPauE$z#kX>TOI{>uEq0+-q8GO?IPKn$zO z_S7j21P>)57LFO!H4qfc8(^DHZB{swIgMRC-`XCQfo7MFFh%6n-fc8KW0{C~075GO zQ=&DBs%?)jyt)6tqtU0F#Q%4AL^`T>)83wHri&-W(r1oGW}N5QYl7#O7BqvtjL^Z0 z)kpaNWiuJtReFV$-D*A zjA;E9B`73qqu&(l!1#gQYA4EwZl$^fG3=OS)2@xaniQevhk#Bzdcr)DQ5eY$T^W3p zB^9$|!(TesRfMqF(!!ArjFcsGRp6;8FmOC}OkNJp0g;4ASvx^b=cG2+UR>nTwtqM)K?w384A88cUK05H^Aj>h+Sn}U z-pZtuR6%|7%awjAj=SjdaXuU&^h`e>Wo?&WS+y57(D$@7rO`l0!arcA4+Ew@2Z2M59}hdbRJE`HS;);q81%W?aU z%zL~U7FmKSiynWCoHj`coqqB+@pu8g9P|Fks{fm7J+G^HGFl3;x#i80Nacn~B{a&8 zHR87LVQ?vvH!xxfXCYcA%Cl8%JgJWjBg`>}q?I>^EWN2);*WAe1^3iXT|H(Qd4KR+ zJXO>Fp(2A$Q}T6TQ{U{onF7BJ!-yL>b!NV#ab0hjqUDBJ*)Hd~??3{L-Lz`TeH48jdPf@NX~an30%dn>G%t*4T~tSVv5 zCXvj{5~&2Tp|%21iuoT3jr%Q(($hc9;#71svsyZG0uCh3kq3!+R8fyOye#&*4aUbR zNxgl2)Rp3&OczoafB5}_`-~F}ah(n^ z2j*~|s0u?<=N)z^MiSw>>k;_ydm-hIJe5E(ZxYmGMN!$Eg!kX3STWNRs~C11eiq_{ z{&eLh=@XDsnwIkT3@M6VZQj=Ap~Sn+=lsBH=$PX_{_Ed#e(BRcOm|q%!29S&3jvh1 zLJ=~;9y77EZr3x_W9kqrUrG|z)hI>CyZH~^WP$B8tt8Z4n--2~<=DDdYA376AfQ6^OZ;H{<>e1*Cqp*9gHH07KUhP=ZZnlPYk!{ET%RVT zrm>|P65kV_J*lco=J&)+Lw__wQ8lfiA{?<;idGzWi-FfVj)==_NbvTeZ)wch8~`AY{jF>`N!y``F<9?qkg# z_2fRpE_7gYA=ppGMVU&^7tQjb(Cm}Px;1w<bJ)G_DVIQs&bGm+kbE$c;g#1cSdXT?qX zJPW2a851)3vrgdG38gVtLcSVWeqd`4ROK90t`FOMWf$^1A+K>Kaq;{(`ObdOO$hhH zj85LJx$|vQY6DV0nlWJgCKMH!gZwpTD>>malLLFpj|UUjNT*vt9K*X$f@5XcU)4Vp z{i5MqjqD^T47qjd!TEugS>D*z9EuX}TwJ`)w8OmG1t3K>G~U#juafa&XiFGSYjjcVMvC zDa+`Kxs5C9&-w`A~q-#Z29j&C&3f48h+CzNiV7p2;*%GUo zALuxfevg`9HeXHXCj+~NC2(>-dhhmZO82i;<#hH^t~qj7oCdYz)=Cz(0#ay^>Ql{= z#eVy|$EonGAS<>b!dY<|7@J^y1~7|D;;BD>Wy$!?z(4{5dIvnW=SspU>*Z||NJjP7 zcubfzEV*L+KkNdyoDbgJMgNQ(OFW(n!atrF04(|_ekdcRa z#2Dh$D`)_^&wuTd(i8cNd5qd*PhbvHfL>u`xrE z7_JrE2`+TmNM>prB?}hSTUrMCpB>r?C|Y&vMD~zW@Ixs!@G zmtI++Y&9@9{4n53$!)*WVzK+vm9o1=tkO9hx>vS^Q zJ{5E8V5Al<2@5?i8^W~9q+1M>;B^{Kj#^n6ymXbLRR-&E}}&-uV57efy$QooU~j?Qv?Uye=nbYod^z zxbQdhfu{iT|4vZ?Ap2qM(4}?qKJPJ3he7t@vXT0WG*qaZnK*u~PZFe7>ggTix22!F zv?Hz^Bln}^p6I4c`(bcfh1~LT)3u)_b+S#S?Bm!}!tkwgYTz@grGk@tEx02A z)5XbnMxsDkBy(y%?N%scz>GF`n4lQENXoh@ztEkL)Td$O>$5f4w46L;G(RagTW9}- zr_IQ)MKFUo#dYp$32dgw+xZrbQ@hnw_Lc$O8by=HYfZ^eR9ChVq7R1ppnqydF(aOd? z%RdNU&(I|wF!AGN{S;>VlzW^ptF0)C^k{lte>wcjgeWu2VY5P&d>B0OWBuJupzR=uh@8RZNH$T|Ok|_f_1u{A&DSyI<`a!T++j=pQ7o3Usa~v&l_>_2+}H@2D_UaC zx6BsOm~`+SG8y?VW%1vF@qbt`sr(MiZ43WsR^``d>+^M_XlkPFC7^Qs}ge+4Ke+`s5VdWB=rzZH5U?XXN8U zRnFRIg$5f#mTahfPIax=yk=_=jt;algO-01;tmrogh^`mB?sGwqd!|KyD$Iz)#P{C z*(zayMa#m*^%AK3wjm3lL=yTR{kMqL%UWbdo$P)nSbYgT@JMGjV=69LNP5D-cy`a! z!%taDbdo$)Qsbp7C1%X$#R{VFvl~UQ+&j=A-V6Mk%ddR@`D+$#R|^fg7;{=_(^w^Z zFF~d*ex*_Ngsfx5ml@V*xlC}|gaYf85JkP}TTCKNv2_y#9)}(ar3A8yP8}|EeMX^D`PpP|5SAg8sulJsY6l z+dE|WbDp=t;#76LQT^AOcbgcizH1}6-A-&PU}L!EpZJkFOt8TK0KyJdr2CJp!djNrF%dI*nNHkseJ_PF_YZqsV0M)haQ{5Dpcet?q80-D4H;Cal!dSD`NRe9rMn zs&OnPXgCLjvsNdGYeo~y%bY6hgB7f+^fHBK{BXpS!O?);3L`ZGRPFShqw9ms_eyU9{SptiPf%$>LD_n9lyS z^N&hy&=K9deGxzHgOo=d$;S0m+HTg0212v==I5ehgoAa9NrXjKO{BGGzFq=c>kue< zFLr3%qAN|fm7jA52gNQT zVfz$(!$#lp-c1if@{_(8vV@<4&+KH2?3zF#^7}h@32rd3M9WRvn6ZB;vpZLG0$&11 zVZkJYOV2#Njn|8O$vNh?C6AxkyP3=`9ksbKcW~6WE^6v=1;X97jAsG4o1k!&gW0GG zM%SIu&Fq$^t?o3@nnCgQ3i61~Vz3ModO>DX80U1B;V!3Qkx&2>ybw9<$!-*2Kj|GV zW{D$FHTj2<#@z+R{o4ID72Ndux5r|%(#bkW5htx`bTU3MrX<7>;!)B3hc7E4uM-j| zmP*;qPf}o$0AHU#rd0pX#j#f{Vt!%i zdGjtN)v#zbqaoas)2E{7`9^!F3Ok$AxkWlZ)mydHFx(0*4ZD4QyNMAS_YuJ!#k}A} z-n5|*1JUKZ%W>Cjvc~7k;E$RA4@)b35Y7BXZ4c-VJb8o6sJrXtJe*CBOg9`D*v;59 zbaM5wgkps1L`W1#VK7*6S=oiP+4@qkUyJr=8^=qjc&+wXw0^6uU}p+oI&P zOQte8@jF72m8Q`2lgs+u4TqFAECd(>{7~2uWf5D6O_h>wL)eiOdc)yzkmTt!eIV7qN5E2TcWJz=fru`t1$U=$0UiZ6#4e zo8M_5JM1reHMcumc}`(~*=TVw61g9i8#XrfJS8>t(FwB`2mYIVJwAZUsb_)#2o>Ya zm)Dxtdx9^VazTWRVb8{ubr%Aht1bz3{G@mtk?iYPyd0~cJ9)&Bvh>U3yR7qk5D+?tmaLFABZ=oB z^DqLJgx$^&KwqnZ!-eNv&TAE&?OK(%S{xs^fDfr6FAU8Mif!na9ryRY?Lt>oQPB$I zz--SHJh_3sYA{fFje0ah3D8}>RooFy3d4B*_T$)hr(T#Q_nTg8zb8f3 zuGBdLGqlbr4Xc(U|Ba3R@UEc1_%GjDpDh%QKb{&UPPE~0xlACWVspkcCX4eo#UE5N zY+E&9LD_gmPaxJaQ86((U!Mt4G0U@t%LOL;fSk1OX$Oz~_A4=Pd!Y^~LK^t?4>|yZ z(MK{3)w@UhgxhAe-Aq;jsGg$Mt09@yn<6SYCLXp_&h5XXR%7NhFNw()%QTLMmj;=) zU_5Mnq{nQeAA7#x1Ju}f+T#0??|7ODAv!dNYsTJ@*e-zpj|4!E&0F1SZ)oc>ua~Yj zx#0r)eCdMYZa^(5YK25w;_e8UFuZlXFgdZ0@A-gu2Ch1fWSh3-YZU7Inv2hs=a^^C5)UXkt)HDKnJnBke z$H$^zxXcQ-RVc&LypE>ZB_n0Sz*oQYlv#od-fq_SZkqM^Q5H3ijCh|#(X`}~aPOCB zL{G}5VC`TNsB`>|)=12n_LX3#SuW&V2g+_fdUGpZjh;po5@r27RvA@!K)m`%B` zr|g3F7Rpp10Cs(vW_YqckrLM6m??)}CJ>+m+wCssRo`HaW&u^@=c`QU*Y8CDhk@Ea z0j3)`l27Q-?(%cEzgetM_zhgM&))pCu-w)4N6gGKC4$h9tv*R7pZD;&_8=6p)Iy9Q zpJnjrQ8|Qvnb4nqaB*Bye4H>Z=q`&3LVmfl?_=af#SdW_({D_*D5| zZsS&$PukzaMJp7t(ZL|3+`4T}#76oQZF+utIN9M{$2~HW{7Ueoc_D_;ySCNiVbB6*^l6&|s zWpFd(w;M?MH< z$A67M-vJv098z}AkB@DaQ^&&=t<)x94nJEQ2|Yi(eIy}q+yvB0^=YCZE7>gPgE+T0 z2&^#X#pb$7x&1BE(ndBf1=%TzVB-{5{#fgN^B5KF`pAnE@$aJJ--P~u)q+=5$k)OG;FA2?JmE9+md>u)6CE+k0hCv74j8?5oUDVu*482?OtKt=Ie>UYfu_fo@ssx|K6iIh8Opq#*Qw%4iXu&Lo{D;= zT-gLmOm$ZL{4YaMH3PGD+6-n9H}gHbsfmYp?0}FwR@z~=vCWZb?Sc)iRWguLs{$4@ z&*$_}rd<3&d?C;$wG>TyQ!RNivej;rE__tmgJ;zG>jr|_UD?FQEm`Dk5I)N*TZ!{yR*j@Kp`^k546e;JX9Egh*tF^SS;P1|d=&ze3jP1Z|le!9{{QjJpBTrQd2aJV7R z71wLE<8KDaKne+>1ubvVzRYxS>TP@bzMA629+PWU$icUVjT)6lZEfEwG9WSeLZ1%T zy==|IgJr~3)^*9q8J99dS3xG12`6CQ2EMmo=xhv`Y*To4Zn@Bc;EV)kl9{$+irgF3Q zXYDc{CQoGDS};^P?6SGhlFLAjmyZLte(}{vtNOTQ9%G5 z1^@<|M(=UZm8T{)tTU&2;VjdXTEj-!-E|BgTmf;-G9J;#6RA)R20t>G+v?ApeC%@U z1yIvb2(ikb7-@D70hyNa>E-%a@NazHye8VY`s3%_o&km*y{Td8wBPs|Rp7RBXt7%p z9zdavysfy2*Ocs|%p@osq|4E=Ip|h(18Cm?uXKuv%u~sGJQE11DX)=(+XHtjn%^gd zO9l=G7{7NgSL-QRR=r?eJV4-Y&hDnE z>JHZ(Dj2iFSQsF!3c}zR7u70FuX%3ms*oihJ`{`6XJ}envbG^EN2TKYxwHZZ7rnXt zmU1f2OJtb0Jhm{+b*S|xMgO{|uW|PmeZ+s$3uHOPGPazuJ*G0zU3XpTE}x=9mv;NF zepQ+j5q$SqqRa^s0uzYRQ}sIq*@ZYoUhlG2-vNzmfAyXf_nfF(xLT@yjbBp~e-IGrhO?>HXwWEuZiv+~K1(rP zkPW6RI+?N`Io0HRe!atgUO^2i;TH-(_sAu8pq7`!wZ9!t15CPUN8k60j)j23-@nCw z-%xnzDgsKE3YfW%J&nztuoZ4SeSO0hFNSYDM&4GKWdmgAun?$k~pPjq=C`z|aEZCv=y2 zo8;Q%TeohFqC6Hv$KUq+oMvAYvds>N1|K~oC*OP3#Z?y!yAowL>nMt`bcigUy=OP^ z=mWFs#A$VMs|{UO7pMNNQlYc=+@T(rS7d!uhGXo}*k<`sR|<-zf8QHUiBGF z-Kme2>_i$U26@MVYLCoO#nB$N`}X|w_{R+v4Mf8+#I2dv*mQ}#Ea#~J}+Nk|Q?M|M!jj~{U&tAZLj zO#MqwFa4>S`CIS%H|qZ1(zq|+<2%F^Z~~`OXi&dsZ8!yjom_eWkbEY{UjI0;_?;IF z*tE2>Q@wCefq=X!3bB?DT_W9pXHmWtKOvi&iL5628Ef2M<&>cB^W3fcDBV?rAM!Lxl>A~5k0Ak{l zmXD{zdzHqFC|0tyi>!XlAN+j-$};L~phy$c;*`k_UuDTW9xa}ou83NEC?z!j zCa&(wk<=$HhH55arSSW%?~iJK8Aq{$%(u$y=gU_-Zg`#2Bb&*b*%e&HhnQQ9uI@3OPw%>K|hU7|D*N zt!!?`A^eY1VmRTJ*UJPhcQHGRhrM`o;h3s{zdKtnGS_h(IRg}mSCjh8pa4*!r=6TT zC(>vf?{I5U?l6KuNQ?vfSe{%6q!;x-Jb6Vs844x@HJs6 zXb;$e*eFr!gIX(VS$oOojXR-Y-)v|QZjZu_!WJj{)uVSSj%1#Ud%d;V+p6W9cyNij zf8uu`^dKTTl$%{||SBQng(0Of0WxKFQyAf%~n+P}twA;zf8l<2x092|bV61s3lAT4V<#nUbdub^-2J2tt?JX6n{7H$}o%Jij-RA^kN zhnaYNOQ%o~$VNy)z2LXOoO{t%zJeSz`n3~(B@l?4V3eTT_q}@4C*f(?#MI>EuM1DqF)IwBQ&;8dqB{m@8#7qAH}&~0 zXR&%ndGlkyf!UJV{@&6tFuK20Q;y-*{N!#HP`G5%yDb%!$a8`CymlMe4#iX;z&i){P69s zaFjl6?*5QP)hQ5^B{58{<76CAX}IsYizY~=(64p(FHOPbai*XwW24}+vzMY<_s@1d zGm_$f*2;JO`srg?az%ZRsGUm|&vZI;6@D1Jt?DYglJabc_af2%oB#etd;E8r5BeP? z?t^-9vnm{Aent&&NtfrAw@(Tnd{XbJ+@z&t#bo21;DMZUIQ2|1#KxBj?|li4cG2yW zXuxB-HcFUg>vG3u%|&MMkO+_CkEiVW$1Pwel*{FIY(9q6~7GXu|1-|!<-Epv2w|_G%VH#(Zi$u0Ntj`E(FPEXkVV0{PJz>^LUlO zQ!b!;$qOgAtvGjpC6r$f4S3bk!0aleLOxvYov_t*-GNUY^iU*FBRuShg((2*v}B`l zDwW%Xr}B}OH=@S`>5_2KKspKkfflf`IfU5MZk@rflY~`fVCS>+S=Iiyp27JkW99j# z4BM7h4YnSLxx&JL$pkwZk>4_u9PIoUl4?Ps$bU<%2r%6#tn_ro6^2`uRK^CECz9S= zig9$=_~n!>`8~(4YvSG?Ev4|#YOw&_2C7s!k>JbJ4dsry~dI2mfubK_Xh9a7NP3fNR`tj1`Bf1?%kOPQwHIS@AsKLZG*p)ioB{N*^O8w+%8EZve=EUmYA@O3u_}=XY}pHzR=?? zW2#|w`Px9{-NBd!uQ}kS;-2Yr^?yiV(GqHtudbyTKe$ryCkLrDSv+L&T_L^0irsTQ zRuf1_U8`>NZcC`r9bRZX=lUA)bQNlzL;b@KQkxZj8Qd4-SKIvo5lw?%J(A?^W~n_R znOkL5nJfflI81VI1|v-LHfSVL*VJ6^yyx05ob<8c3Eh6V+x5mis+yy%?d!*%t3UwD z^^E=r=NwjEdgR3tE|=?>C=^ld7Th4+?GNj=sgV!Z<`>Xy2y3AK?q+k77WMsdRL>(I z#;~)C(E0k_f9Z^$SwgnFLVXYUKw*{wd&~{Qs7^%=gS~eF8!D@ML7O<*K2=1sW#_^9au91Xb2q5JnOp69eh@xXiL78dW4lR=MH&o2jJiEAje zxIiO@?%uoGZ_)yM2-(f<;rm{*k5nj0$9sXiJYtjv8e5cDF$`&IO-L{L>AAa=+{Nm* z8=hW<#Cy^RiHv_RGA@|1BkitW)2LAduzG?b+}9EAcezYFWD_x++Jou4wgkv;v;ZJ? za%)`;uW~WZ`1UtfC@hXXh|5DBO3Hb<9$h^%zUW5IW&tIWl1O%t;@7Q##jBRKw&AeU zYAK5PO}ASXIY4ww=Kk9CI=qi6CDmsFvBw1g62b-3RP1R2f$X*p+!p9hsJgp)DJw7= z{wGaco;{%8LYsB@BOu3|cbRR|U+E|aADsDvZNOi~?8I%DBv92Yl1iYfDvk{}nt1A* zrjqWNskUXC8hp$&mv&*vPrI4)<`vHK^gn z*MTsz6H52xL5Iy|CRY#KKc-sYI8SX9m()>6BsT#2WzYYUjWoBjxz}R%^_wZ6l%kOaz zy%x=%7kyB@4l#64AyR3GK1szT{LVnIewn~;kK>34TRi^6?ZZzcIl;8(OV$3eFp>aB zIR78OMWNDv%|CvTH2c{J7xk8O1 z*>!+{K6;%<#_0gLH?pST(mAi_6!TKM7NlMpi1haLDKFY_34tmAOah~P-?N!*wCWMI zZqM4pTa(dR5@q6*)5972J67|ZHR-q>euf9p96k8vzv!~BSM#StC-OP>YM3~k?DX&T z4lr~)h#fXE$_4U(VFkcI>(_e4$mi=YWeltX-kM{!GZM60{5Y&ix-An8#QEcko9ed< zg#>!)r@6wN>NuFam<$@!p^o^FnY#Rn*7_M=(3>WJ-8Hk^pECQwim!&iLdFC3J%+7N zsz0LnLEA*%QYD)nD5TLF62TMUe(NGHhg=n@hS2$#G?FC)ybZ2Da6ei zL8v8N85>m?n0j_HC-&wwaV!H|e%$M~<9+t+=XjO|Ce9CQ>#8Xc`L^O5*D4*0jc@Cg zwCQDasOt7l(=0P$3AG# z?w=-f+eM9KataQ-OdW&gr>F`Ca2GFPmPdClP+g5vnks@C>?8`Xd+&r=OMt!XfdoP# z@xEX+?aaadBJ8W9x=g!vRS*G@mhMJMkdj6~N)SY)8>G8i=}svTP*SBqx}-rml(FMbmN$JgV`xE))Y-6Gg_0i%CO{M|#ISTSV zNPe=_3!{C2Hg|Y zXa<@;WnAsU#78t>k?mjmO7Y6Tcq;w^yWcl5cHuW2ZyJT_k~t0Jz@OCGP-JF*kdLZwiL-8%1w z3HG3jZ0l7UBbhrYe@wQ^((xx=X>kMM>+*4VdRHY*Om{0C1lIawGcQmeIcY=anWd>h z@kHG=UTv)3(bS-nQgR7qrI>Dse4h#gmOw#@+tNPTs;s1f9;4L;`A-fg9HqSLkhbM% zuz-*oF!46L*CRK*JYTlHE(*N;bw+N7?Z7VF@{d`AA z(gcx-V`AVk81XzjJe-Gi&&1j;_EX)rUUi9u%`({#{MCYG6KfGNMYxf1!Xb*7rNOzmsH6B2r6 z)&d(F-IG7(Xlm;D7cTt0cFqP@%;EZL;l@WNwfdp6eRYISf3}F;Y#;Zu+!q=7QqC(} z|15jBo_@`M`7Y}1vfLe`l7$v=tlv&`V*9@e22xY$1F6y&T!%Y~17;Tz=SPlHa`3DE zj(@;W%$6Rq1g6^3@H}5OFLZ4d_vc6=vk3uanW;}wLC1KT$=)Lh4{iny@$n|hkixQC ztuxAPMUR}cZDX#N|jux#21bkb;b%hY5b{-M^1SB%4z2#CCai+ zWHUIJ;IW6?61_^HWIsFTQarb8qy}?_i-X%YP}bJO4;W>azg~a&@a|A6K zp^Q76cJ7G_-XEFhFXImi8fQt9Ck}1siG6rf*tg<({#Ee$8!{&WL7sTh?Q>NGpN zVll2>vTTP-#IjV{`eg=B!}G&wp702zT)oF+HaVgbCZ;+P3q6PN>5-Q|Z|Ro!C$mLO z+aZ2*tFAXcBYac8?L=@gV^rjxdJvzge<^!qAX{!YR*xB#{LF%?i32OH;YcI-8F?H+ zkz+u}UD@w^wW5y$*a>pW52|bIQUr!)S1vVq%kpkcAl*6aQea%VgMT|?)h#YbBe5DW zq$T!V+-vU5j_}MP=4ag14!7Bqz<5!MceMLnGAgSkxYs~W1Cy2mN zMe4PiX7{by7W>a$^q+(Be_(Ph*@cSKD6T4ialUMEzJ%Mt7P>vc&dx|*4}iyLP`UcH zNa#D$G+33G@wfn7`7RimjtL1Vags&n>y!1v7IzBx!j*_9<*2;JI81Pj3nj=f^X^*p ztJl00=8#^EGTL+%HpwBRkjB<%`>ggLro+H~Bf(rdoZAfXfD16?M?xVnOp{t~s)QCL zQ>gfhLcaXU5One{)Exd1-0ty9vqoxd$V@zsZfXSgSGMpwr7r^8y`7L%R2wl9_6!Jz zbcfkyw@Z)lGO+T1hrE_S+)`<1jKbVfhlISG?=nT=y`>4H6A^(*bQmAxY4>K5rLgC; zLcUDj)Soxlx;lAX&+*jq@J8J7AapfOmo-aD1~K!zFLPdjCM+)V1JNjD+x@%C*Kd8? zH?VBB?mjB7MFT77_3e5-v-kS?(jb+J@rC1baX>qO3%*h>bEM9yBfk^NuRpttu2`O? zoFLX_K8C#*^yW2}V$q+RlsiiSKlv;IJCYDX0Mez-*+3uZ#zyjK*!vie_I_5k&)h*p zO_O{=$F^i<(X^xUS6qB*F-r(IKuD%|(!Jv?ik%#T5!|wDEbK}b3?IJR+DYN)Gj~!| z%duFk(x~lgC9s~%V{xwBbw$jTji1rJGHX=U&P=5NXq2R_d8f&ahq39?c`)uk!&UVg zgm1&Oe^V!JMYcjceM({v`6>k(Ep?rZ{GB#7dlJmO^kGzK@*y3;8-cc4vl!I7GTZlFqq*>AO z6Z8gf7$zm#pKZ19a!;NB99I|4x{DQc_H}0|!Z_LG-uO{R&w94?3_J6%$4qK`5p!@r zYBPCq7W@E!mt;uW&s(_S7S+^rEq2Bqq+wRd=~j!5eABHYgAyPZ;xOT!2>1%5R>38< z`JMBvlkG8{1mM+yPd=KHF(r-19c;H5?R=Z3NygidwZb}jdE>z?-~{aK?1oHB1O8M$ zpc=-Yl}d{Q(LOTwYxuJaWS*${lb24n!`5cwzNvWn)2!fdn`M0MISXpvu#A6kT6(|n z6mp`rzu`biNtefi#e9JiMLMAqrepmWK!fx)BS0Ot7~)jg#T%}wscGoxskO%hVw``# zaz1M#RbtDL#!gka`NKTR`g_Z!1)bH)?M|eJJ)ufJm-}!nBg|WkhKG1F-5nJWZ5Qd~ ztQ079lzjL^a!0upKtA-(zJ%Ogdb@TDua%y&cojid*oSkTzjHKQ(QMRyR z=DWj{Q+KHUzQ9ycZ91Wt=7?_~mBlxZCpOw{7H{_ufEf(xEc%)F2A_1_piVvHgMo=b z5mFbR#8CVxTd`us3h?--fl|)tZv)9GxSfrlCT9tce9GQ1Mx`qUjlWng!5^#hK+yO? z)jhw|2k~V?aq?#s!Op!qnH#N`j%vIn&Bw-m8ms|^t4!LqSG1xcUKT+WgUvm-F!vM+ zT$N2bf#(8@XBDxEWAXBe!aF$mPPNH_?X_^)4{(G(3p$}%*?a$)CvRYRO&+`v$&Tj- zk+W4O`74va zX2hyRv02LX)~T3{C;&oZr1U^aM4vPrchD}sL0Nx>Y*Q}=Qkf6WqvZ0}IM~@mi&UD+ zEbavgOtj&eJcIcd)QvQv;+9J{TBx7bFJJx$8vz#|(L@D1imP}Y^vI@>5(|#y&;DZ0 zSo9uq0}tW+%ckOaD)oqGT*vc^2ZO06_o6?w{Rx?#*&X(RdEIuo^ScEotLNwEKWO~} zP>Fml8xE-b&{#=V89{Ob&(YEIyT2rdc^JnOw3>+!Tj83uOgmk7C4@5p#UQV1R z4{siV$P{W4rym1RZfEUS;P6^Pfk)U%3;rs72goAGjxEw}9{nt1_e+)k)?Z5gcLPjT z#yH)Vg2?@9z#Ft&^kgmN-z;~IB$AlmVwRd-`wz}YL)kG}mf5K=z)?(-n-_^Bcx~4Z zs4`5Q2B`mXg)?pq+_kF(ET%ss{56Oqha#@tZZ@iN#0vVstQYJkKfdhQkdj*OEQfwI6kXX2{IK2MxUikl`64m2q-7t+s+W=Zl& z+E9osY^%}PPcNVA=LTeC{8XukwXvqP|bXbW6{D zAgL0L7^>}d4LRmZbeO#lXwzP6A~@5JZ!=IC|CXL3C|79cz%4Tr_d)ysmOdJA-6UcE!PDrlrz*nuCD<#VM{LYz*%xtpQ_IFatku>iW z2Tn{mGD@$&6bBa}zRae1^9+E`jI4`fWlqWPYc&#c zEbDvK@?5MOKMlVBK3wf|o9)f^PkSww+jSQf-m&++DJX)e0BB~APb1VXOlE449u|st zIm~%&jQ)Rug8m~wCJ97kg+=HDAD`UjPnwQiBx-Bx!MiCoVTtYZ>c*)&$Xo%1TIo%{IxS-!S;y#Stm)iE(RrhWBJD@e;-Zhr~d_dzjMVfkC7{dfh32C1FJ6v&W`fbfH(1 z9p2j7T5ew6Y73<;ar8qPcrMo#!j_Kv4OKR@K0wceJ<~BNzShT`T3TeM`C&C0h@s+YCuXSLc?zdZ)$rVDH~H|S#HE)_p^%Ss9bb#$ zvH=76nhOk?PoR+|3yzK#J^6L;TN~f=8ioJg4#f>cxSdCSRDeM37KxE;oSFIE?3XRO z?rD}uUxt6fMY2}4K2@6p>v{o0#e{LM@pahHTXhEA%IlnrjF|{I7;vCqUVz!Dq8(GV z@hw~+-~ny8;pfrTz9r19!IVf>sJc%`&seDu=TV~c@~5Hsct6e03*mg@Um!}j#i-># zvc_u39GN^Jp?jpu-1gb+L||jj3j3&<$N;Odyba-kbxrt$8$!H_ADuxK0%~WckbUnX zm<}h_J?A`=4qIY)m@#etVF%n8%ft_8w*U+scqbij0ey5|6}&6L(%ZxsHnSkxteZOZ zN1!OUc5{Y+mBu_bnhs0;bB!TSWtAq}pZp~l^&FxT7X5Y3(J-Q-M3b_`bXd>)xcO94 z(uM>y<^dNKX<|;BXo}Smj<)!aSmqSZl1SocXb#dYtVV|K@QtFSLgKQJpVZN7&i_M&iZ)ya~x)9IEW8!DV#BCYF9ea@^-d$gC%9{;cJ%q<>@H50<{M(x|ZL*e{Zjl8-2Mi=r~!4F7{!= z&H5%7GYO)9n?}+cwvH7^ng#7K#Rqt^2Pct1%A!QZ~m>qFM59~d{To` zF{IH}fez1RzCyiNqth1b#VYxdL-{zM#$0y__rNVGE^ho+wMfR(t$w#?xcy*WCBHhe zv$vb%2U7$#7xzjYm_Q7^l;5f4J{Z=996&(EVy2yNjgn9eEd4CT5p~<=e)7R8XWnqG zAls{Ho^HN|F>DoXPlsEb2b-oY0K_||4~pjz0caWX<;F|#&ChW6Yw(JmofG?Z(*ceI z=|t}Wb}N^hNU7@AC?Mg(?GjB_f1}Ea?H?)+Rn`8x;tSlqdG{LMgo)lX#-dmLkwEO# z25<*lY?hy&U?U-}G4VyXN{;VXE7W{wtvI1_q${^rn~RW#5`uZ;23{GQUk;nfG!S^G zUH7b3Yxwb9mv#ik%<^Ipqf2HJ?5J^%Kp=&y)iR1Kfc0rT;JGVOno2=cUZN@k5DKE1 zEX@UGIbXPNrQ7)LHkOE@GvzBXKcDB==H`W`7X^j8wQQ4zw$U`7U*{B6RD6-fiz1Z` zqY`WWLTq3RRy@aY9tNk%v2ELV6kE+C)5itx#@~P~&b)P;*|GA)Ee-~kO2r0gg4XYR z>h5q1!17~KEmvG8PtUmS|#wm z5Oxz%5YRR>Tx5Qyo-b&_84iN}xbvc7=o-kGnopmMRkyW6gVO+w)pc=DBNh*HFc%IH z7V@#VU~zB4K&6=2C6LC&$z{U<^n+L_xVABe(b#iKarcaz76L+@*XWxk%aByXH)o4P!hoQY z1C8tJ)@(>l*mVmRc;EYrIGL(^895FjdjQhDY<7^1>t3pZI5gLHffGH48JhH_zu2LC zfy#x)1BAm3J@HaLWEWwyX>mR2Q~5Ng5P~(p(AW`gV+;H$IPjmqUmiLSTy8M%E_70k z0{Unv%dm*KN3~syWfMf90uok+WSs|$>mIlTd^S#7xhCq(31_j{ZzeTi&-mQG1`lJAH5GJ*br9D|- z`Z$LS*GXq7im4go;eau2M#BFYktDoGV8^D*K*>xer>H-Qn$=q71T?;wP}`8GSgxSK z7xbqUkl*qetN^XM959dpeGish6cZVUWS(4<%`i!8z>9KAE9Y$c6H)hc!twkK z$u+VSNrM9ER5M!cziFt->jfv6R|^Hmt?W_FLdpV?)FnP@-1IU>?d-+=J-ouA1xD0+ zHSLioNyJ0b$5;>qTp;jdbvp)PQ<`cAkmdj&$H>=OrnD7qsRekP!=~H^Jd)4X8*R7p zrN)`Ut{*PY*g%Bt?dLQnmm#T(mtBqspc#Mk3|m@NW-n`LKNFJkoTkP&u1&7NEICt#0*w=3Ds{uqRfshttMWu@_jmd1a}JSGW8*Db}2A zyv&+(nH0Zj;`{7k*-v-N4djVPq?;W-QR(FFEV3S*w&2EP>F-A=8VRnH!!~bBDBW{Vo~xx%ja*iYW-qmc%H$d>+0q8o;BpkQX>S}iTg z+jc<940*saOEf$Ti?M6amcnEkL=}2XkEwggFPAy$Tf|?>&w?}w^uhfsd9-_5?)|#4 zve4arIoSnW{NJyyjfi3Twr=DNhQE`-qwb>Z(yi{732kYncO zV{0jGN7JB4M+-#K56#ikZk|2=7w`SA-~3y~E{oCibc5|tKy|xSx(JD zGOBvS3|1h({A;Q!3bWYi$X}edz1$!ZK0{PShAB-4Uz<()&Mg54QZGc$+-Dl?mZ z)oRUA$?~%s3r2k1(9bTj_fEO4ab5^6bB+m9P66d#CiPZ&;ZeKT)yLXDyr5~GIezSF zc6a~v()59o`FNIE9tQ_U8h%iF-sb0QM#Yk+MElmo5)%V?wO)Xk@)zBOq5}b7+~0fc z)aS_#A<%Dtp?UWam}**!%N>$yelkF}uA>Ty=|1(kFG10y-42=%7|Do>suE{vx-k3R z_hz!+9so%bPZH1bo17Q>0bVUKulb1_w}s=RF20ck<;PNWAFyBUg~8t@6T%s0zSQXb2Dxd0-aae6G-j%IfA3p>F$6_-xpd#!p&kJ_glPVLLK z>aHvy?cE@kK_NC98D+ja=8RjmlCun#S9D$QfJif9`<{9UFB9}|4+R9)-5XN#fjy0n z!Txe5(_H%5goS=3*=stWHD>W70rNRd2X^$lEY}FURU5I(#^5)2~T3I?#!^MF=F4_A@f;d;L~Tp1a)4U|zCD7v^MqxUGsyBya=PXcsHNDb^>SoYyTiMXJk zitoRjH-0K4gPpeWAuVJ7&sB9kh#6Ui?aC~bj6*5W#pXKWgS1_4M=uD5XO4N@DBi3|~e2`ltVclkdL_#x653vH|?Z83vm# zKC+zKelKGFs9{t1OdqT451<8`kse8Ms@_KWUx3m!ik zB2H{fO~~B&{d|R069{#{?myg!qU?uw-_{`V7(~HhrRNF)$B1#Mq(2=>YtbC@1KIJe zCE;eXqe$b$WC><`3$y*eFhFo;Pb?t9Eh_3tOLK8g8Ax4_vN>fcs>DI)-CTQEcK>$p zb=I&|ZXc8ii0bR(JE8;d0TV)K2YoZ9@3gfZmVmhq=3p!P=&ljw%Mo1g%uyumw82l-vvF?fJVl!jm7pa|^*37XpNxRDe}?4UxGr#TzGk#Q>w_chTl~ z>I6BbAMfn8?of@>q9A}G!=^qYhHW;s&2mG~1l0MWjJvTGCZGt-2{lo$5+&IOG=t_s zs0<+1`~EX;yD96pfKT;?p(43+xgX!dfWCzJ?sY)3`gL0>$WzSmeC?b#L&R}d^t>oB z&lN$lc9!be0q5fpX0GVNO0~r(rw2A4FpPz=Lj=Ga#;8$r+?t}x95sw2JSg0+RnI!? z7OqZ@I<_94rWj^k#|pLX?Q5DtvY&nCXd$BI2W;Q|Hz(fc&gDsKyvHfBY|kv!uy6V3 zMah>-{ywswvLwE(D~{=}JoRe0Yy4nZxs@PPy2D^1PaQ>HN}VMwhF+RY+n=U#Ys+}h za{h8f(%x&22PH&8Z<<~jdw|np22~4bymkAJ>%UB+e<_i#EjIrlCv6}1gHxuDaD!jF zvB#jya<;X#2e+_9;su52FBCQ62RCZ{Eyke`$C?D9H60e#$&aYCjo?AZXmTx&Ar@H6 zyGGDVaIb^uhH_1|CH$q%CWycH)c7ZNDDs_y`F6iAKWEXz^()g~8bA?KbKJ$@RTuZ?P zWjuVED;j*#ALt;VQiU75gB*|NK1ojG_G^Enrlpj_9^h^5F#zidq?l7e)DT^!Hnkd|; za^BIr{VDT>G@C`#I1tZ`OGGvVvkRThnd;2joM3LfCVy-_AZiIF-}`T;b}Q}xBMiAo zMo6kf8*OIc*NWHU`A6S->ZOeUPO0`!D)@r<(vhak26iOCDhGjy<)^QgAdCbQ(TrrS zsBR&sU&9C|towWL8z9>Tvy_N8(VIg;d`fA;64Wa6=&r!72n&S>`tk@CT`&*UZ>w|4 z*LE$|Uy8l1yHdtI6mDI|zvOm2Jmv8&W)9ISl8UDJVEoUt<;W~d|0s0F0N<_3g%Uzn zMWYh@h1zA>U_G^DGU`RD2P>mO80-kVJOKi=*A0n7j3tKt188F^X zsoT2Ersyju{M`M7qrVwZky{pMTbs~>x05Kmi(|V?f6c?!bMU`@^Iw5{{1V+nHswK! zZ>&RJ6|U#0SKQ=}A$`9>C^lgRc}zt6X1==ZEg|?j0ui-tM-Wk8=HON#I`K_cmD{o? zv}nU^*9|f$fQv0;PLl`QMNgQe6eHDLSj6J4)>X5*T((n3`U#!&bi^Mw_`cI zF|F+2+c4T4tcNfK(nm&R@s#DuSj^Me<@Q0BV~gb%E+lPTy}fYt2B4D;glH__(M)pN zl%u?bn{auz{9FZ^5S9pC^Q13D@+#WHZ>Rpe5kw1g%j@3je;itS(e~soRqM4gTaHpi z^;5Ys*0PA|^ifoDWx>dr&E>hve{Ag#us>zG3yo>f9&PYh_?$ucw;Mw<3o^Ww*gApy za&z*e3H_f!+TBo-xK3s52!7;+&%dG%u#*V8<`X+$G~2MVQV`xDg3MiN$T@km0C9F2 z%NlmL63i?t{idb7uKQo;)WscXJg^05qB%d~Bl>s;;wB%DzNuSQWL{7)bL6gm!re)0 z`H)5Nqk`G@kw1>4)9MS*-4bK$5W1&iPYbK3fCR87@XC}<82VGHK#tOn~|A*Jsuz#sz{ zI=0oXo=Cr0cE=Dp*Su4+_-i-kh^eBx!H3-btW{^oqhD(w%LNp#)3%mJua{I$rs5N>281&m4&{RHM6h4( zu+2sEp#8Q9C@gjXGtrDP9S~2Sp*91Ncz9>Hi7&hfHtlN7P?a-4(#h!q*s`$UHgZB0 zw>EjYdTY3iE1>b0nEQ8m)F>3!k3>Fhal=UbPL`Y$p$o6P`9vr;6+uSizJzld4D-e|?P;IefW zog+o|Ya!R2saAq$$0VqeY53X`ze8N)2FfiXq^BWagSd?h zY2>~zrP#E|e8na_(iP6e0w9#FYY zJ&&+LFLX3~3{~;KKeK+=p~`p|8_gBv#w>>ef)DSo`xIbCoqgR}zFz^o0i*D)5G*57 z%MKp|?V}BWPIU^Mhyg*kS^C>Wt1EV<>5E5vdwZcC$Ajxv<5!HalEQ)NbuK7kuqH?6 z@dYb&uX{8^WKNj$X?{pAcYb%+_!!cAA@Jq{I0mg&u}g=we)KFsV&Tru^a|=21Nx(D zt*bIDW_WEa^Xj8J%6Mla9m+M+_U(F84LFppZU5hUlAFm>^@iCl_(Q!G_6Rzs6zz;E zg`h=j5A7X*JXSa@$iMMGZBy^slQy^tK2KOQ%jOuBw1F>y)o{HE1jcyl-TR?yQ$6y6 zo(?4RG34eYe{zV1)VtF>Bfd=j7(usmAu%gycOEAcgU}I3-2%_|*z$AplY157WVjII zZ_eET=J~R)>wR)AU-ns3vpseYO|WAikKoOl={PcNm2k+kM7Z`_4q4hZv4QN~Jb3J0 zm25mnwAP2TCY~6686NJrKf0H5bu%XQ{1r_2bFoh?-OppQ?DMV^6RKaOEv}~&gyH8-h3`OY5 z0m3W#zhlFPW3r(Cjkd%wa>s|`R`^Ro5ee`PXI2o7K=8vvK@<&&DCP`r6|=g5I!}N! zXs@Ut4K?Of&7WG98xAtmys_-?DFDm~yx+DY7Y5aM4dtiH-?H!-(mxWC1EpT!`JL>Q zpSPkpX#@2HB(<;N&#J^^y*&IrmEC#^%4?Qa<@+D#uc-sK_gxEQL{@drj5e7sGG(DS z3>}A{z3a&w?7C_Z{_Jsy=!bA8@uKC5be{ZjVxxZeg1IiWg*@rzr}N`aeJo${`ass_ zv~#QB=dF#CM}Tn*XsZ&Ok2bnQKWyFA{Ahl2ymtHa&lMQ91qQw4^>rdCG-CDk+kX*aYjHl<$h%Y8-8F)1=cBuH3?2V=pUt*vprtPz#)eJ*xoTBB8zgcqIFdJZ$Co=!lUnbBMINpq zfRBmnu`0h77Clu_Z{S5A4VvV|_|c8L=N1t??Y93r93d@`0-3WPkd{@M5(~#tV@f~y z^5?iMMDKM+659<4ziMnPsLOoFQr^-t38j=%Iu&gn7;8mP`nXf5rdiN$?l9#*ao*!q z{hBpKH{->`hay$ljreAN`Zmc;clt+kS_HEi1 z9HBXI#r%!bk6(*O5~P`P@)*$Uz!nL52>R5!Pp=H<`ouMd*_8MjRy!|(RBwDtTMrF<0M$#}p(U0OgnU5>6K@al`_`Oii?MKf%=adVJD@pkS zT8kM;c>R@=Kb3Pxp3OS47OtIk*S2-r78aH+d>2gK za4`^k9eG@H_AlHnnQKcWU}lGf5bui0&Yeb*Qp@Q?Bfh+%mb*_+wM*7UZ}PFg2g8NfsffJW>Pp^;&XS*K6y)bRmsapkV#XA|EqG==w_~ZLhSPq#?$L zZqor!HCVrya!#htf1UTt6gHq;C$-l|{A@c102+&_2+L&ntaz>>Y1Ux@6rw(?=F)PQ zOSx1l5C~Q#%lxkT+aoiu0`~Q7HoCax?7`-$##2a&>*X`4_ zB${=HknyL~x5v2BiCHa_EtyhWwA|HIs=qWROO<~|$GYKRCyu-mS$C>GnkeaQx+m;1 zM|Det>YWJlbT2dNmv#}7`pwj{tGz9fEAm`ZpLV;Q4@|yIWR4Cp6SbSP(si=yl{zX3 zi$tavi8mIrBNSA4CGn%6UN z@BxLvrSR9b&dHFu7WeSV)l>TViWkQP_2Ea8ThYFht@^C3Om83hTE>qY1*I{td~2}@ zJwZlA$4KIp-@cW4X$@=ra0PM2F>d#Z{o_k?Ujb7P{*fRqqA2En{_@SEk$%=^ffa_t zaJTD;!(QJ`Q@yY*-UEWlTcU2seH&3U>@tKL$ly*#LqcHgOjFB~2|#YtSH-|d`$0`$ zFLh3kqtN(OUU&c>Ma_?+ax|TRUb4?>-suAeruR1Qfiq`@-Ht=e5~{p@_->-nL%Xxi zPzgo}0*QUi_~6?;WE?eE=oR6uSW|y2(sX<^lN$2n1dGiUBa$hFOGLKjIMNrB#HTPH zDZdxR^lcO8UGMi?mb4dkC#GJ0c-85ZvRjGosEu$BCtE1wm5GAT9AJ)4JgW`$Y{xMC3q=d~jccPPo{WVkRP;Z@w(Ryp$t>(Cm>fZz#pcM;-GYb%B zg?7_)`e;!Rx}IRAZ`LHFRPHN>GO>Qv>y3iDhU@0K|0Qhs8i$@ShE4-X=GQ89GBG6 z54pJm1+79FWTR=$=JGsjNakH`Uew7pF5L?^U;cT4-Y@p=v-BTF?7vSH;w)y2IF^=M znDq#J^0}t^<|%u~rpt~FL^%qC#OnuqG@scJ3WE$)If?F>mVU7Jrx3_Lco>AjN9^0g z`tya#BGH@A?ddg%#>#8Bc=GAY0iSB0_GyWc?ZGLKTtPRfzYz2OP1G{K%#bYL)f?Zk z$u-B@TE?99jTRQl$b@qGPEIJBGh>DM^M*aP9lRT{t`_@J-yzgS&b6 zV={#R>uLOy?nSnjICdxl8Glx>E895l*FGbYIhVTa`>A(}=u1zmpi;2q974 zmHz5|?tWv2c{&n4=1x6V*AFkg(k!Jm-Wgdq*nRv6{`}T4Ouncfs|>8W2XNr z2An%&y7gk%{sULu6zhT0YAxd`PgUvU_0hB0dqw%AObC!-W&A)lNN6sKiOy17GDh8O z^Tg|66ZeHJ+j#n7>`%Wo_8NXkG%`e^yQ68;*@P^XhIK1` zc<7{Pe&(3_qG9&9k+bxtPc6$!;!GMD_R}7x?fN~^=zingnjl$Pl-9Aakr`SDudJsV zuXh@5A#hsgCq}0~k8K{6_^TR;V@Uk<1w{&u)b-bYRVJuXf%;H6bn8Q+I_HP7**~6B zSH4#wCN^)blkBs=KGVB#+W)W_s8VCj=pHy2+*nY84fUMfsxs&dXDRrfNU?oo4mh7c zS$`4RPC8@7j1z{$f#xqb&6`3Xypr4*EH4&gTNh~A z?41+wS0tG+&p*E>c{~*$jrh7wd}l;8SI@8ikKCy;TckJ^gWp)=jYNgu<`3q za=)PdIqypQ50n5luTXs`V0BxaELybu9ROb^}B6oZ`LP zzT1sVT&05t*%93_d^MqicN|^0>@a<6ycX#cnGue8D{L>g^W@n`>x(*q$D)trIFt%( zZQ}+eGh*N6QL$oyBHxKQ1T5h}?>3%%4HB&w;HAj%m?W39KYLBm^ zzEVPtJHpC4|$c3gcpdSY%65`EopZ{i=TwlM^S)ehqtv_cfP|OS_70k* zrxfpcOscTN&Pt-BBTJ5epDIJlF{N$+Et>=u;%vV2nyfRiY=R$$pWma1^TmK_xoDb- zeA$BGm1%mHE!=@D%%rr<^zPVqj#Ec#?iV*q!6Ea{_yMM zv5`y(on@uB7scFd_(jY)E-3Pj+etCQYk2;>q2ssK{>ra+>hf>RX<;0hX;UB1Vn}=I zjIRl__B5;=X_b3|g5n}8+b!b26$}H^Wno(do zM8+e;S)057#n53bTKhW*e%OwcWlY0dySG0kQZo$deFv)+9)g0XGl?@XlRl29mAL06 zZwtKbOPBn}#Qu~nZL`f2oTaAsn>Y=v{WM1*F~6MW2$x&l0X1F4HDj2Wv+!S)~xIz|bp)cRM;#CoTuW{D$c(q69zG{=!~k{Y0AJ47;r-oa;FEsy_Yb zif8}Wm|~Xx>YGA>@Vi%Eu@0;Et>BxX8*KZENwCJx@2?I%latd`jk6E5*4a+#41H}G z8L1%P7}pr31lQr4BF-K*?7*jDddi`vw?#(?3u^tRwVIf58A%=o@#&nJeV_w_*GC}_ zH6(TDIzkBEZeleuWDOES{8kvgo1f{|_EDv_)=P@jgitxHO%iH9a$k)K_Yi10e4*(u zDwo1m(Hftr4N+b_3`lAv*N?$>z`&0j{Ype1(IxbQD`p3O#$(IPS^J8we|L9kk3l)#Q;EI?BsbPrr#SA&$k@s3i)w z4BrZ;4O`keluG1G(xHkGYRpFAoRN9DB|9(Z-DlzrQ_Ve3=ep6|OP+1Lj%Gu^0hc!$ z(wKK)b){YO!!eaK*kScFM;13CRez~OyQPq1^`nRU>8#ial#;a&+(<9$n#hleKR+yR1o7DSWUr|C9_Nd`!8sI5v;Sfoi}LZ3G0%W@Ej;);^!KYN}YETLd3 z>-PRdvvgM4wg5H14M%NS4|7}42hc*PAF`i8uq$KQITz>QJ1_Y4t zubi);>*A8ASJeJhDLWxCF$x{WH$Vhi0C5I*i zr}hQWLgo-?zn&?bKEWiL_m=9@qTYR)(DL97)S~!Tufxx~unNte=G|{hA$W`0nE(8W zrctvdwAvPdTKm)G`f__O$)qs32xFH!%6lq;{lX`yYI(lN%?wSEH}S|G+dQN)&d012 z?9#xh7P1>Q$|FNM8BKpLFXR{1`AAJ$&v}g_bMU$T$YVlG(UDA-Y1etT{el`v?6#LZ zUcsl?o~u#49<%-W!&!_Z9=A#q8n?{*st<(@`yX-s;Y#~NK?)7alm=!MLZc^sG(nDr zmkzZ|^^3NzayaxTqUEs8e4yTmlEfaxl~e&WN28@{tDCFyYp;U9A>!r$mp_m2532&W zlPD1wNQj`Fee=fOU5M>S3E+0c2BLbvfrm;^%P4T=bNaj4^>>H+Fk$BYw zB{drbWfb}-!U9Rso{{|aMCIW5abAeN7@FSDNWM3}oEEMw?p~{3=lN2BXShre#S%^g zpNSl{_rry}BUU&ht^RaBM`~s(PD+~yNRrLA&ttN`C<{*|Nyl`rwGtEWUoA~HUo~Jz zX*jVt4ZK+oAFrj=BNuh2OI(|CX->zICcw_i$M)R5IeWH+qg5|IVJaG}aGv9J|EvXH zv2r4gF!McC5Y9xDWVvvAZm(Vv*_+=V!HD=iK9bs;c%MMqUIkq&!CBYtm}h#+q(zJO!$~@bN5~_ zeXoMorR+%NH~X%eB7{hO=|;fe(HdLzUCiA3#^ym-V<mf?dqtL36NgS9{2{4T^ zW+~t+Wef!g-GWx2bzdNoU=?|d^ui&d@SZBFq`c7B$I0)lN9xG}{l-##lN9J;E{wqx z6L+Ku2CC1w;i#Xi--V-!vA=x49k=~EUJBbfD*_fOx>9HpWu?;MAd2$l2HsrJ8YO6E z-#r9OM+hO|2ALP=l|ae*3COJleX?`a%*?WZOi7* z(AV#WD`!IZY+4He!snEd;Uu#y_}Urc8@qpU3Sb#=i(b@xTf{#OqwU#o@;!>ieEE3+ zy%Mr&jTZY|@u|R1gEZk(3k*nL!7d*M3j$;k*#}Yx#2r|RaIX94>L_OyI(GbMFC^Wy zYqK#ObndTJTi2?OW(TcY)0+6ixlHeTcf_vZk3!$x!u zWo#{yW@Pb{-nHnhX5wFyM$q)+k1cZrffRwl&npdEXE*x`@BAbSe?OYJOO%^`c30L=v z+f6-TTjhuRm=b`qSz|==rX4IDRUEQiqC>q6zf8Oe)W6#F3RX%LOnB@VJ(D-xYE|%= z`L2d~nV7 z5Fztm^Ie?xj?U5)v+3+FWPpZK#I`&5{Xp1r{?_tya(zb`>`+NQtF*w>x)U;dR?Vin zRPRmRaR_m^bX3(mvp!uRp^xa9@|vqiq@nk@IdxRuJ5%l%VxW(3c&s5u5@7I1h#qG) zVE2sY>^22q7&5D--hP``=n(+(P|Iuz?$lw3iWIB5OWpY6Fr*D30kNpB38HVr8D`os zN@Jf>=%oMpJV+c#^GU&p_{IN-O~Lj4U&w-E;;ePM-(CC)*MkS8YGLj|slR3J_}nb0 zzvL?^DRDo@(Oz61Epbkf{H!n|DSV1GT%f%?QlxK7E{-X5bH`X@1SEj^%6}3TPpNBD zRKMx)x}-(PLahiABSiecDF(yJf#QDt zo6oaAE}xy=hYGn`H2Pu9&dtp^!;h_;rAAr}?e`CN+N2Ag#h6kC+-DkPLa8pv-k#VI zwQc&5_@RmUz2jn)yodkKljr>&SIaQ&y`9#IX~6W={Gndo-D>9bq|Zd}e$G(pnE>4P zvTY<3AICTWxLBzjX`3> zV%ABmS@A6;8`@~m7LJ$i?83v4MZs!(4qFL$`K(O`(X2G}DxCd3O}BgF<#vg<1zm_O*eL3V`@q z08vRNc=deHZl0YVW$o-V^$)GPn3S*bjmZ@;QJ>5+Ki+Y-kf28!Wg#$n7?)@!_n%zM zG?1Cdnb^;x<7J%b_o6j1{)=xtIns{&*#G<@Zv}5(3OHI1(Fh{)t8r}ZLEoSMN2ISp zawy-uyG<(gJp%cgN@k^QY>ENSL|&K~pQBVOaU=QK2?%Z1fxYGq5P&}9*6m#(6gB4ykQ47Ra80eUP zik*p__WVdw_WDoqk|oC_#)i|OT!J)3`ZG0c!QCQVS_AMTp?2jr7!yuzITqj$|GNCc z3fW5f;K%M{h}>gID1b)Q#4y}bGBKq$%!w_DEx#4`eke8zcj{O+XCxVFiWt<<1KFDA z-4GE&lsNh@piHMHTqfL(-pN4p6sR1F;sfdh93tr*|AxudI5xWPs1$uzxX;~oVMJN^ z+trHA3ygBiXrsJ~w#|Qk%c2~tFt*=CBEo2Lg46iumFe%*ZSH^PWu(y*2sbaz0<6_f zZaxZLg6!4L)4K(~3?zt6cQYJE;4f2(!+AJP=M23Bp|^uwIiEcBt#;XB)q~1MCq`~s z8p)n2Q~Nc=6Mc%6UisU3HAwkiwX5;1LC`WxtsM85YNZ7(L>~vgEt5UrFIO|MqvTMlW0%@N2i`kv1mkw;bTGD=t zZwt!rfN8{Uk}G;NDyQr(3j7(VQ~DjQ6cY2aKp^AqyBDflN`b_yL1Y29-vLm;xB4A# zhI)4CPV^(8-SzRR?rZzRd)g2s4oK4$Ew$wkb9N@c$;{aG~^G{nczduoV*)UmOLFk^%;&3}jR4ZQa{qWI7 zgRm6@jHl{c?6|8SP9OU3oLL7&5m4Fr@0_92%J=@Q@w71pH#tN2jB!qE)=2xG@Z`h? z&7vQy6es-WSkz_SUhn3a%OR`sQgyDYs{CbutJu%*xZG$QBy+$`U%5ZRV?gPe7Prcf8OGAwV-{-%(b#4 zY3oP2N?&$#%Aj@aR*TBwj`;9hI{G4`e4i!O?F8BgTw5a|WuyCgDYrWQ%n#Id&i5ND zb-HQ~OZCyhpP)mVJ!AQT;|1?%klz}kS|$&;w%Os`a%4Lb@4EH|uj4I51g0=7BA zZ05@*c^vQboH!Rwo5zBJ#mGc2zP11Hif6TEE3x$XL$3NlUc+d`id+1nKG|=~1)sNH zh@}1Uus{0TkN!)N)?Rxqp+bge84>$z8_JvEdk#OROQU1*gpj25rf;RFB z_Antk4^Cj0k8uu$n+2qt3^*nKe?9J)2IN!3%Mr|S0{b?pEo@wjLp2jha@~L0Y)QNZI z3hqoTvFA;oJDhrXw3J4FgjIs?1h%O9ZC!Uh?C0c`m^j$f%T+$|M1~4p-$LB(xgHIV z<5R;e?m0cncn31$hpktv6%zoP&j1L2%={w4o<6v;`DpY>lr>xhCX><3-zMw~$BwhMqAuQvCS^CRYEK+zXl z6m2O1;PAKiPhz}9wZvUKInXOLJ&PWWx<-YD8}?O)lT)r&dn!BeMDS^$1a-&GuQ*W- z5c=r(+pNQUdel*JVqI!4h%3)8V~%=)EFxO*t(NyHj3zHKg;@=5k{u-2Ku$T1FB|;b zy3dFdo$^cl_d!sdI$WNa@FnzCqRjACR+Q6+pVvcMPk_ZOdQ{_FR!MTXL!f8gokJih z{C+kF;sKW-Pd^(xK`3Du0zSldoXh~Url0g3(nvL&Xe$|xeB@0{9yTxcw4!3N`TIP% zHlra<#+!@h=_x1)t{uozq01BNJ`)x|7CF?;_aqi5-bo z20y&jzX6gZ#9I={JHOlDG%q?oxaExVVQT|cnokYvqv>2LnJWL>C?@c@ z?1g&A#m77eWCnqAQ@ifvn$)xC)$0|qTrbZSH5`l;<^oh~;OY0X%WX8h=rVAjYF!6EOZK^;qGgfcTn}gyH>H%tp3!g%bWK z#0b9s^0df-o&c%4eZEZu5~ad&?w>e5uy@1u5@62z%C{JmTrUnUXU%?Y#TJ#^3jo=G zB*|x!l3{15n+fVGCKh1(Nv)N|E|OWgf`iBB8E%zan>({vz?Owc&@Kp_mocSCCH06x z=wE=dn=LH73GUO0==smIM z81IOjclw17TV`g4ZNYtbTrdIzCl9V)G*%lGu3y-0De_&SPa+y@AIV#SP4D&{BJU zD*eHsJ%=gqomqg>c6jUtWVlhMW zC7!2BdYIzS%YK9Ynn3e0O>*JRF>TXU_bM~<7Qa5pM^ z$o^BQv@rwFaDCw7fu^U?WoY2~eixiV4VL2%xa|!q!rUxDn9w-Zn51eX=c_@&+TArP zj5IL}sQeXgqdJ3un&%bY9?_)s*?#Sj^X=*g?Ozd){O#)R@|0#L;FC*LfA-Ggld#r7 zZ{R%MZYBv8VW2!WpX#Y*X4x$W3cQEag<3%Xo%6){ZnVEkq2YD#?|`p)F15mHw2%uy3c`*Y`P$OoVSp*0q%3c%Hh%DXNfy2683;{F~A3e5Z-2?c^>L_Vc)F!AXz_ z4{kx0GLgICKHW~FW;OhrT$s0fO^4P-A6U*>wRF#tXaHw-KQ}5rK|N1?dtz;Jj4g|p zEcm{5p++ud3!yY-!`X&y9t(^B-#N(n>h)oV&^oA|dYtVjz7q=R@xCd?*w^Pb7%0w3 zBPTT{)4Zvmf}e{D$Y_1>u9DN^yxkvmRo3a|{*Iq@g67Tl7FUwo4eyiT;Hhr;LLv2ns4OPnb^^ zW^R5$JJ(5%c-~=W!lImOn?+L4%P6c5=^u}!nG)1*jGaJ9_jH7g>!9jJsgjaomXII6+oX*tSniRPT|wdWoP)W$vlBK= zv$0L{&JnXfOTJrKCXwf|Vm1vZ4jfvL0GWyTwT?d!+ zUU;?Z3KSV>RitbAsp#Sp{GahF^@uI=XoO?NkI61~PCS=?uMbIfhP>GcuO!tM(}K(- z;cY3f)jO4kHWA~PA+~a`_jtO1CN$AbXew=G z;$`W~KgzM=E%F)tiKrAV4aK`P(RPG5EDAfd>S;n#NqQT&D2i?JkzmWKPr>^;Ag-C> zIyd@uxb|EF#ZhGw!ZAah(n&p2&$x2E{l&`qHpaZCu9@=o)EW>H$IVemC{wOnPcOxg zZW3)KzN)!7`f8Y8gqkmlr9kXoE?_zWP?@Whu$aoN*b>oa1^H))HnjC@?OKUt!S|ZS zKAU9z;AR~5OP=gm^&6D5MQN{BOOI^jkPMve0a?K7__*cHE8~~r*|H=hP3iiUL``Ub za!ydU!2$IW$puI(P&cmDIkWdvu8XNfIeQBIN_2#%!~1 zhgzGl4Z(QVjcSrilz`Mix#?*^-gBx7n$+jy-RE_DZXNWW1FO0eY#S+NQZZfQEP*Ik zLlSsL++t0@)F508{292WJzbR7{pg)wuzq=mmxP8Dxjf=T7l-sLoYxsXlt@y>m#u9akV!#Lu0wO9!=2NrypJD3@pLlZ0O(<|zaz96A3L_#IELpy*E>b| zi^ZgXZw*k9;;Kzk0`Gvr$CeB@Fbq<2kfC~){3HAEB-pO2zveC!-Z<6F8`A}quNawj z?y0(@d@tMVr(5aPA$L$zYZQ}v<{?M@)sVNVDFx-3dt#xOW^~`?q3}|@jyNgBqK!X) z#MPxx)Q*_k)%0{=YTw`IxmXM~4x_yw8sAWirh-SLVuT(w>t@wews*`im`Q){NpL?e zseaEB4#!c@!zIMT*wy)=|!cR|~%sBx!#5?XA@Z58G3}PM66{Y$HXY>ztGMM(Z*sscn;j&;i zHB_MwRWb)~SB1AqHjg4j-Yc^T+PJbcLSiLPrTkv_L61aiso54dk)g#W_}nAO^W5Tp z8$*(YFfEK}YNY0SH-D@+Ttu_7f3^lOu?2B!Eh`n!W8OA%=%Ug>4s7qUm809J@5f3V z{y5ckNua!qIdJ6HTg`p?w(mrm)OFzuSja&>OU>BiBT!fRUxlVAH27SdsejGB8^U;{2h9Y-qgD*&!97_kDCZ?;tt z4yl59z}s4RfTzs*w22J2rDJKHP-0&l(o_EIb#$l%bgFX;W0)v-kNVNhpYG{9tvf-` zfsUn65(>t|qsW}kUsK< z-zcbHWplH3jY%H3t>K?{tnO2dcdW9aqM~-P{Soi9l+Khf8Lot~Q#^6Cea8>?(`HXF zNlbvgP~u=5q0t7;0?@`>JRTeZihL%(n$09B+UM_Uqr*4QU{w@KK)|mj+$_glR47@Q z`E&TZX~`84=$R46n&Hq(r3C%kS4Nzi;Llw8F^)C%5^O82iiq#oSm*rkBd}CQ#+05# zeK-^1n|>Nga()+uA_u@st7R-#N}+j~I) zC-Mx1qL?JDF4U&cr`@Wi<;sJrvfkiF>D`;|&!bx>UDH!kO6}tZ18Be$>?*7#(^rB~ z)Vz#h69(XUn&04iKjjykO}`E+eSNhp3#IId$XHz=e#^a35&;fhg2tNaH2>qG1*yk0=9WNkZE9qSHP&q!NmqA@}MKK|PMo^!YDh(@yNiXi4C7ZH>d9r`iVG z)8cj&zVbmPI(|2a>k{I-Ir_owU>s~jVIX(PwSZ3SPEU@mAaDZ$vh>*_KB?#3q2}yE z)#7$e__oaGFsZFTqH_clo9vCBHss$>tGp2gJkFob-FwW2D@0{Os$YGE8W!vub9XyS zrLAP+o)!V}GT>QW>jsFBwt+J9)+(9n^#GnIk=EzsN}%a#u&DM=Xm-nMVfqZunSWYm z!JV8s3cx9a$AbCvN-J3=dW5Dc;Ba{h_`iVs!cv3>V7e9^?)-5T$p#mS$S0}hL8QD| z+$iKe_von0aG1*kPj~J59noTZ#JIUjY-%VOGwvEcW>G&Jw1-3{?Mokfaa@JBg(RFH}#z3ZGE8UBb|`b8r%v z7~s%Si_1#z$bR?^1)xQ1NpUCP&rI#B3i()PF-ggU(#rt8jqA7!$Bo&P2uv(LA|&>= zd2!_)^>Rgz_-jIu1-gRHDN2-kbHI{zfy zd8wWkSK3Bl_7P6fz+0kVIw2P0y_)2V=kj+ z74+5>PUPrIXS3C&$J|_fFjMv`nzhE<7crigYIOdar@t!?rrE2XCZ#~hU^o?incn=| zp2Cziof9!DKN@Jbk@|dZ82dx}T+R#w>v=J!FU9yb(R4sxDRhWL%8#=vhA0eZ%nS6v z-#-FIdWVkhp7i7L`;t&IrDX#ld<2zwh8v$5z~yAX=n|)pf?1Wak-Uc&16(BRw44Yr8=+=`SFYTWY~ zH$Ae~Nq`6`NeOU!3Owuu(TUH6Pm5fJ77sglx5B`z_+=(q%f+lwOUOgW#=9n)yoR*~ z*8mZd%?mYqk%v>131cEBC)3;e*D_+p`n(MmH4KZy-+)nC!CT^~Ng>LI!*|R3QIQT0 zO~=_Y(9TJiRWm{04Tu(N$p9@PE5pHPz$?fJ4!tS!k{tIaH4h)7FBDbc9GvAT=pvLA z^`x>P4_6#T0wJj3`V!L3G>k29n!+)X7pCe0vaaxeeOU-)SJ0}pta{6Sd+_RcvVTsCEMbF!&TM?VEFmE4|L`u zU8T3=%Eki2);LC~llG%4^(Qry_N8u>g)q$s>jeTL)Jr;I^t_PzUy|ZcRw(I_hLS!u zbBtEstr}WL*vAfJG##qemOM03EXB?=;iXw;fXUwB=v|tVQyul!1hC!nYzAhvKA+$@ z(di28T3mRJ&MPs2UM-N2ZK zIX87zeo=Jd8=onBd@s>8UP|g1h2!e*FBDB+LR{fHTF94^#n${LqjJNf1 zt2IEB0>k2zu|WigZ*vT{?$fZO4c=Y8CT#ulNjZG)63_#7OFAFSN?u8C+q*hv<(!`J zf}9q;+(DaVOdZPio!}ESH5m2A43Dy8n}6?n*7Z}gNV-&H%2iK6yP9U>Pv(bcLrEM`n5-R7q}Uta>(ZVt)dCPIVrwz2a}rt;>}{U}5YczK zAy*WiPMr1@D;raJ4qPkG`YK(=F%>TI>vuCWmiHF-p}+|A;j753HO6(#zUh7N%D^gTgfiwr)jEbPR+45^ z3B;*5bLGNnK2}JbPFu4>xFC>voAO@Kc?{hake!2GqwY0dFu5D0_2=qC~Pf=u9< zz3`x!nF`=h!r%XVPT8-fMZWr@7a|LMmjvhPe+HJLvWy{#rP+d z^#^XaRLX)F12v`3sfye!uqm#+R6~L7Eld}i3A+_yRs(Z^O4-kM7S6`dp|n>T-jv#H z7$SS7>AE)h0C-J(wmk3|9q4gr&ufNyHc)GfNhVeCW5Fp-g12`~so_ zICj|mNGw~G)QRz>9|5Q#pe*SEVp90dA~25@-|x5vb%xIzO7|{!80mz(Dj(%h{~kag ziiCub&X>VayXNTyN;);Ma0EPbF8^>jz`|#S;6I%Ru2tX8}=Me5bO|d_512q`Vxh+tA>{W*=G=}%R$pjj>C1-|)zeE%A%8qGl|oXJkRkdHsn;rN zhn5H-2Q(hc1P>ZX!Xxa=4KXjvBnXYSoRB6o7Wbs2K z^ss7R4o^%@BcxB{yMV~iwByKn)J#)Ot)>X|#{X-TeSjcQ?Z21Hq`B7hIF+GPgp+vH zE|$Vj-8D`afa*cfZ>dE~CRa!Fyx)f*<{<0C6a+T50|b>HKIAqW3Xj`4`3cm!f;7d6 zC>35rGK}4N1u06;E4fqUlBSZYESyC1SgXnzXB!Y8=aP2VEEPCxp%!PE%5Pv`u;N{f zO_Aal3}@XzQuf2F{>8de*xC%PPa|{|@qB7g1=T0t*%*%!NIQQLpt?>tDNwqToS(w> z0$Zz9^0ZAPa%Zp}x}yLvG7L=Z6q1C|42Pbid=JSTdaP7+=u5FoJY;p@IQGZGr@UM2 z#TgOzz6{xaMh5!$T*)((iw22_rL(}sYlQUm_vgcN_6^g{E_&2gGm(r4qC@M0v}O%= zZEbCbLnZIYCGG`56%|U40GK?=jN%2w6I`pLfPi~)^86E7eEUy?lSYg(Q&O%W2f)f5 z{R(h-N=2?!(T{Mo;#*mr#{OY<9u?KxA3M|a%u(V>^w5_vk$1zv<8(-{b>P(%6*Fod zu%}tiKdx(&=mQ*Bu2uiAXk2C^$z>Oc@FE?jTlME3AZRBqv`xt9)y-5E-w{pEP{Otl zB(H-sknr;1D76@FjxKLj@wr_^bhEYPr%qBV7p>_D%_HtPxNOXIYRV4f#AiAiFNJ0Q zxB+}!^#gVlYs@W0{&>PD_?T!{DHDhmBgZg<7FfT*ju?t3Ved1Ovm^W!06%>jb28JF zjD!bY16-|fWti%qj#cwGTo&=R$PKm&1K<$*`$4k0`$0=}#iX4BwgR4Uo^j!gF zZ7q4Zz67Jd$t0IwJ-+Op!*qk-H;Bl>Y&p{tBw^$$UybRT4czZI855hKWI|J&?+T#Q;c!E` z`T4pY_>T7u1ca+iRI5@8y^YBRPw#pu*byOAR3p%yqA9&_`nF$UAt3MP&fx}v;R?&U z%l@$$0&*%O6J#HJCqSIF4Y*MKZz~%>5(Bulr2`Eu{F3*aT%I!V9~+%zXs_c-=t455 z##BgyQlT%ek}jrm$ji2z#T9A3f-yv$aAz2LCJ?TM$LK`OF@iX|!68RJi5MZ5af zowc(W-UyIwvB@AZDmP7fp^7vKSEndZTL*2t;oik%X{_q18u?2jh%QIjVRf}20e_an3wTgm;*Y^ zcdf6o-cRbNCz@(aZ-+}+61^0N?LwtYhd3FutC^1zjWG0;vW8OJL$Zm{2vn_nbo>(U z#BV)9{UHjxKX6G(-eUju?mnw+&hpm6W3U8kjD+H}$=yoPq_LOltD@LcWgqUWqkV0E z7a!Eno_W2QHu-Kqw3g#{uuf%p+zH=-svl`eZFX+FCGMT7 zJsE|SZSovoZrT%QFR>XfYtotByDO@s)RL#2g>QltNMQGJ(XIeU%Klz}@}%k5;EFNZ zK(PR^nARjei{tYJcjWJ~`;b%W_z6y>2`_!}ybr*LeWGb-Yj0Uo_RghSK$JjI^=2AC zsM(bbH6Rm8jCQ8Cb25tuX&>;};1W!yGeUcSTd@?&;oC?_pH6f651b7=hWAC4)V%o{ zre$M@BJYPGi6EZqbSWSs739^+$1`0z4P4j zD&9%f+!(7O)dTbAoMlufCLZ$Xa1r^DNXJ6o$;#}uaka|Hyp}6>|0%|=(o-bObk#qu zMAQzx0|U?10k<5(SV?U%k1{4_z}!Fx`D(dlIaldqKC0I1|0tBQ zH)LP%lw~<9RJEZso?KTnu+mTw?E-Rf8#Tav&+uH`%f&1K?KVo^>&~HxYZYVA4yK%+ z{5!iD+xSQLDdCD$V3Z0ftO{$J5o%kbvzb)2uQkQx^02H$iM0*uvpRr8)m0d9|2(Jnl<6l@bu(%J(=!6sdwtat z#La7Uz?}@ZT?J%6WQ3%tSXWiw2eR9o@m-1w)=>&YJpr0k`3I*#8L?CDh}EVMU(pYY1@^W{@qbMgzmL1F_u{w>{RQ)&$RZ za$hA|HkvnZMl(jOwl*y)ycp(&xf_r%Oy~!2*Ez}`q>;qxdL0ScWSgq_)TnT0;Y^V5 zJWROtjd_d(lkpQCWU*^Q+AF|4XrhE3**w?k901cz7qpVk>r7+IkPe& z%Bl+fIAG>e6deL&(ZXSkJ0IBiz5hL&k!(1V5<%{x94v zqis*7t!_Zf34#Wp2g&)ZNfyDGA;gkrD;DN_>K6x@vg}aipV&f7Z$7>_-QX9+jXFG^ zDdYa8FyM*Y_B9bN#c99I>oW*al-7f!t*fAtzftTP+)}DA@qEyhfsUy36WkV=5bl0y z1|3NCriARf%_FFU-~0PQvKpVRSGdf1uqOBm^7o*r3Thme%)Z^*bUR=;a0^LWn1@U| zr}q1)Mh}L}{?q9kOyV~UIq4VtU8U%On+TuNYEJvF|55cY*DWhZT+bp%pfnv)2u;*o z9H{eWJ{|O@l@6400AGjc+Fr8`%cJjqvpolhpr2MTJ@ygzry)pKYl&&yyLlPJ3p1ri z22+NZ%H;=)K!g=F^N$o`p?pw(zq^4iT^f-kPm5N_BoLjwFG10Lci0?U9^B}&`hW%7 zVpo>UbbaM0lZptl0%b+Rn>M(QRAZOQ*!8Q_O$o}&2emDgOY}IB%XsWvob8lF{Q693 zOC?nlYY~r0UTa)0EjfbjRmEd64}7tQ-5p8L(Q<K7(xt*77mtEPFI*(xES>Ef(R@ksd$fqNB(Ir=3dHT1=T zS#fn0Cq~>m_@7=vq;Y;&o9*v{WFBBMp34M^xHkrmQzc~+aX%mIexLIZ4N~%i;+F84 zfx=W{MZ5qmh3YF8R<+*SpR#5)Oa+!OW4v%}vaf%AeeN30g2EQ>G7c)0#4DHX#IKLK zHyY5}?cZ{u1+XyQX?Y41femQ8^zS~~<)TK6G*eS9`!d|Zv;m$nm$Tr?(h?o7_h=OXRz z;X)%-hWYs-C);W(ipDtSt;E6vYOE^V1kiqy7K2}&Kr{yoO2@X&sL^t6pEE2>2J4lu zEKmTY6iA5}tlB)NbXl%wLHZ4<(D<5;R8~}sr1~ham7Avt;5Vq??v~ub`e=h-=z99- zw~X=XMgYP}9OMChZE_Qs>SjC8?iivLJH*SrI>cs3@BpC3c5UWP4EAPOhFOeHq*b0E zo^!m^;`?fuo^X z@{6aj11JM}!pz5vT%ZuwSlWDh;9S-q7zmTcT7drp6pg)$h4cqsL6x#->Ix|{;1;5i zS4SoCC=x&KyW%9Z2I9NYT^sk}GsJyyX*X0}y~SJPQ=@39w>GUv<6Z1$1&Nt#e|Y@Y zQM4SpbWNz|A(0>seciNa|g+@$O3z$V&i;uhbT5|ab*HS&E(XRdN{B_Op0 z-XM;F)%ITpz@tmH#emDR4n@%ptXkidVoF78u5SCd9Lo6jQUOHt9ISO=u`D*{g`r-t zK7h|c&Lb%o>-GQnbk@fKeb`<50R1O)6c3Khxh`o+_-YFhlsNe0?%x8D)Fok{8L>Va z)kh#^#gBPERXVUDs&}tu=zGYVvD8IftyXFx8m2m}!(4rkKd6 zE1m1A=k$0uzj^fo0CKe>C5;Z>QI5Ub(lOXlC^-uN?I?d7!Y%K|^JVzk3pE}W8qM;I zO0uMoH)e!munyo{sqXqobxvqd8sf5v5d3+NBH+L&|DbNol03fk%uPRdb#Z5poZ;9T zKk-*>LpCT5)XmMq0!eGr&IOYiAys;)4|ciceSnM|?8%Vo*Nis2 z27uiJ>ya;Uh~FwVM_3gAvlv*Fu^~I@#+CbNuJa>rZ(m=Y?4w%ka&uUtfdVK1fx04u z1J}V7nYbO&*o2U$VplTTe1N<-_A=!{r5(NomF-93NS;zl8v-%)nCZ1(usF$##<65> zK5!RleBOrxNxCt@XJ2;7ZL%Z!ln_z%CYQXHw=J!WAj^2Pe&=)&cd298o$sHqps_sDZby^vlBuIZr7c}(?}OMhQ3o%K@`O!#s)J;&^J&P&Q0+i3!9udNrpL0WsbYgdQs+1OcYPZ771 zK~Q$k{cwK#0curLehgpR1NTY;1RTt7rtX2BpEDrYC6hnJIp|D&H)kYgb61OHWWiuS zvFmQg#y_ql#UmSm@X)JyQGTO|6`FAstUuSsq-Oq3J1J1x-GfQzkv}SIx)B$Dh|CSw zq#bNXx1ir@U|L1ck0#|cVYM2cFGBYZWSjpC8;lm^xrBsNI^2(oR5@MNqPGSN^x^V0B!OG0T&g2f-yJ_%LO4GZp5C1o-#ecXhjtLF^^KFI zc+Q-%G;=dEHJv|hu@ulw|80Pzu!xI`1E%Y>wcE$Nmy`9LhC-L=+kUUt&De@S2JIy_ zL{3O*5u@o=wMO{*C+~JOFW47QJ|70}+6h=hOYBjdQ9CfDG*pK*d+q+AcFWy;ah!Qz z!9bD=k$SjBt=yk*V80a1SMTP#F@16s<=dPHfoKvB$^AcW}#d-REvW zsay;Lv`s!0=}-GN?IOAP!usx?EizNh23!QsLw4?Ml^cXiZ6*iB$sV~s{~J7i?aZn1 z@o~__gvDYxLuOzRvyCLo)ZDD{(gAhnr;q31eET1Pl`^`h@TqsR`+Gr526fQ>gL?~qp6ZIZrmhE+LR!B!7<|9`1i#cor8bO;( zv19p_|LW?S;@z-My>C1!-dM3QY0+>cb|`+8bZHzQf7zZ;{fJiROx+cs5MIF{@50QR zmV|_&D~cG3J#5fTRJ~${?#i2-fv*pG^#YOr`9giG{UR;sALTNJ?PpPI*!|aCfBu1C z)7EXdh~?zfebE?)77`8UL+vOX100X6>H?V$Sxw}}c*kD0eL}A#_?2%z0*h2F6;(Z2 z3ZFdub9JHAVzwPi43{gLT1R2q-i4#m(Q7|ZSdd}K;2kVC92aDQoz9oHw` z*p8Cb6i{8*J-ff&7`#DOGJr^zbQxF_Rl9#N@|~h@)xi7Yx7~@MgJ?d1tOz< zy^k+G{^pr37RJ)@EhyA2_y})iVV03BRut=sD7EGxF<(r2h~jk1xMR zUQlLP)4^?3TQ=N4Yo9-a9N<^htd4IvEZaIZ z_6t*iQEK~nBUXQF%0!Pl3|Gk9U$opS9?OW+Y53bGXuDv?!!@YBozlWG%++I)}$6eN)&A{xd%|F7ETH5N`45y))0~=uGmd zI~nn#RBN`EFZ}7uyQE-Jp_b|BmPI;KR#;gMO+okRA_Ni`Vb7`RpZe< z@lT?SbMx;f7w^mt&5`9J$CD!FPZvo=O-R&F{CvpPD5Wv`SGL#eRcndHPT9eIS`}ul z%KpFWk|vu?-Igm?e!}gNDLZAB3+IMq=^AvcK>NP>VW*mi<|OVJXtq*sIrC#`yhrB8 zrtcYrtBVUAcaJcym95WNlX68)*-M)p33pt zq4z;V>v_IyC6Oa|3u(@V(||gZDz4Y%NLFE()i*EBD&2g)x!blCl};EbF!oMA3bgl7 zrgq+bc+C^^aDfrfD}>H=dwUQC3S0jC)7y9TM6^JhGTH)LLa0=67h)Pr7me|oQPU*RSiDdAt zGOL$XIiF;u0`zFV$a7-ujQmc(4{Q@G{63oO^@pcl;)#IAY15H?Lz4PKwk((r76g9p zn=avlfwMblm-#9v*wiy=4Wk(HjG4LV2pZaQL{t9RH?2zai9R(dR)h-PP zJ(jAW)$(!YOX#!bY8+N8QT{RiauNKORs6TKa5?+<=fAN)or$?RA|dOsa0aB7OW2n@ zWHUn!{bBx#mnl?eSu;gw6Gi5VQVG3_SkbtB`}Sk>SwM)vu?v`wBF(rOp;fn*IP>Gt z!p}~=n}k-#zcktiWDQdWrGI9^8kT?)gNKXZ>^|p3n`6R&J##5>eai`d(7YPvaLFqb zkPyrnMRJ440<%9aP}{cEUYz33vVt}qc~qepJM2EdZ?}CmxedC%&;#vfe&kLX&^Mf( zV)*0|<=xx89xR;EV<6`Z2>gE9FY<@7U$wD3J!`ep{YnRqLW+FbI@x}9Q6RJ6a1zh- z=33Z`7}D5HT{$BCG38X%>!GGQ8Q0JF_WY!Yc`?Y(#UKhOQ}SNzosAOI5(qaywhDfF zhq@3P81?H?XxZ&!>XeMmb@54z$~=i!a(5XR_+J(6H!W(?%p7Bf`-C8r8#=knO=wu zHEk532VGU5SpPNbm|beEc$ek9%qx;l60V4yUNv)41FMmn%R*95vDll`NHG{B|K=yLZyrtwWeBQ#(Egb8yLqE&$8AxyxHrDjE$vEsN-eDe)4|Bo|8zfO zHHKde&7i-x9o<(JGW#fcV8Al9!{;iGYYpUJBt(6)WzX%MFpTf)>zEFY5byC{uAP;T z48`++wNu};*L-9DnaeK1YhNn#Xffm(%;YtgaCC;9;q}{pdbQeEdnz|Xd`~_qn6Y#B zkMgNwN}JIDyfXWqW~cv`0{;Ku6%qlJl1lq_N4EzQ$s8boNDYP}@kJI?p^&}1M>fIh znBb_gU{cXR_|a@g=N=KiXqn6tbpJIh%}?TaTOY74w@5?9>aTgznZOwA#f>bWk-2hkblg`OFQkeLyS) zno+;#*n5yH5gED)l+%FSPPwJ$#R{AIvKsxl9}lj3&{a=Upt&TRi~)m?PV*b_s`5RB z%okaD?^m(-3U+bl+f&aMS8s?011*$9I<0^PHv%4|V>00eCXcb^qd~%>wLoEYXT50Z~B1yO!qD5o@z=LbV`a#bsrn z(Y`sd%Z-#k%=*>?}_xY84vxUHxdKCEr= z=wI7p{dV^sKZ`yb^eFumcC%=@PF9EVV_ffSHHQ3E4E|G9_b1fedG)z-Y6GMrzw5(9 zKkjY1%huw6LYrIAqD^<+L2U=m?A&!!3mC+4RMVp3wa%sn$%i-VgeH`m@tYal!|quKInCDgrj5**7$bYcTiOO`=>--^&P-fyRl}|LT9LbA%Fv78TYssmct!rp9rBapGa_ z$$T65u?C$hHN)NhRIVWz$H%`c9T6mo2fgEMgi(CH!_Z*S0r0b__+eG)4BVtpP%03Enrs0l|PSd@`we!O_!%y3!E<~qyIP}89plZY`t>wH+Ua!jy&OvC~ zH(tun>m`O7e^vT4C|YhE3tgRpO+rj+M7hy>RF#)sZYtx`tBq= zTRO?JyJ%zlqZMq|`=8enZMsk}t0N&DmRSG}s+;MLx1M{TDSy~*(Y zq`#0K12|9_UDxm5m<5HWx6kmI*zZ1q)*1QEhqA-PYmMluOCfgS~T>ng`xef1c9tDOS5suV>Dg^_O zS&?ftIcALH1OK@IPS26wV9cOr(mn!my~#g*2y||AQRIZwxO!nWL=*SIhx%o14m!13 zC-lH%3}0hor@6h^@d~Xn;YZ4V)#ZQT+y7$C`VYbNfA8{sgLJFYg57jRxhC|qs9 z@$DjjOg75Bon7D>kQ+??nUX5NcuIw!(f%qK3QW7@H?L!k9=-fW>)7MDx6MaNhH;VH zme*Q!&!M?m9zV%^@2BABR9Alxb10W|6mrD5c@%PJar+Q=ryWn0c?+ z$I0GP-N6cMCT22Pvz=;je74oKo%VZR7T9AEz~$AKFa@0=TcFJw)Gz*Hm`PztAR-f^ zW%&dj=qUuG0xn`_gA2uz?WPSUD-^13pTS+AZv>jNTcZ4yWMue`$AytD_!Blk8el~R z*EQ_i)YPv5EQGoimeD4(!A+x^M-M2lKBk%Qtog2(2Zz6qh!wre=o4JwFnoi2{|(}f zqI>)AB|1PnDnfkpUKRPhRC|;1!LRrEKSgGM!{s$>|6a>W6=vu(N0fU~spz*us2;Pf zf_ro~_Nw0a?u3ED;ps(#fh^7Q(0jJOxji=2L^vt4_jPhS}*O^0Jx*{AX7L{#LbY8*6i>Y4w@=H073!{(5sd zG{H7}=BQt1kE*mMy6$Q*{n)>*T|o`fz}rmB#q22^t^0oSa``BzrW+Qae+5D-2v0BG zu-woWUf4?*fDRxja|NC9K9reDJU-?sGkzuL zc|G6ZxlN>DbxJoVQiiDJ3(SpEZQo5rmd_CDJR zt4EZ9xQ|!le_-tY^WXmtY+v)77_z@N=x}kL%eMKYdB#LdsDo|xnFK6;Co@3Xw9jH#9U(nKu;+@C^XX7!r1?#cIXBxFv)5JwY zEv*3K>?mNXYhUrB3Bggr+)EbtNB&^e2K-eH$+{3&TH)!$;0i_UICmHZTA2Z}pdZm< z^=3KyGKbNlScXjs$tk-k?hT^jSx8FEi}X(S=WDJ5uD9;z)zpYn3dyP`*91{59J{X^}&+{y=;^H zv`<5LhUZ6r9mx!NlP`x?PbOSd1m;DUHvN7SPAqX*rgHrn z0O%mM1H1xL` z@PEWm=1!eILM57&ofZf+HL=SWc{Oa9q#^An-85_dt}uiwm>6ELp7_5sT>sf}fl?9? zDuy`4UxmX;td_+TB&&}Ib~}$`f%r4I2r-3j(fT6 zeUJhG&bMxEUz?D;+L{Z5KOGi96zG*Vjof3HB7kMJ>cNIylJ)KpQ)fGSlG-=mX5Jlu z$pr5*Qpky!vYjj1E=Qhc0z45CqDiv0wqcA!k6Ju0kq#0UX@z*w61imD-F>H3P|b!{ zt^lv;H8?mYCW*_T-x1jKIWLA7V|7Zsgw5=?DiB?2jrwH_q_2O_#HYWwNEABJ15SiU zN;3HZ31Jz+Z}b$W*qCBTo1pC@u+24{!oQd{hp3>oeU%-vR3KS?PoXe3$eCuYjBgk6Jg0q4$(=Ub^p%b?@WpI8Gf+xLM5>mS-{sY}0Y`z6115iSbqkFU7ck|E+J zBnLa}mc73p+Uz-1-4&82A}Ye-H155+K9dhr^)=^2O)`ycd!%IedG`S6|1(D5@%9to zI}`VWJdrGfY5#A{{l6Ogzc}&#$@BRQFr=zp?B%irz;M9Tb$4c91Q?D3^Az9+ABD=2 zV)5fOAMkJhaPkl2mlUYn5ez$Kc#Ov0Z*95nJ#>nBT5c9U=1g8O{|LLsK#q{+5%6+{ zwYj2}X%$_rDC#C(w%#ZyumToKJ6~GJNqynHYzMtDOL%FoxycvT%2Y`^-;;>Kt>u){cFtE;9{13^+s$^o#vEU0GLAOM}YuZSgk0ix{JRE^%wc ziI3))x?oZ7j?S1`a!$v*rk$>CTu6d6YXPGeuxG+L{@Ukl@^r z5ZV}PI^+N~Vsph~z$&+Gy{&&Z_k+`(Oae=R*Q#OQ>1FFRV&T#jxNbwesG78%j=?LE z3N%WAHkYx3^Va#-RohD`P2#@veMK8(VDI~bw%#ox1j{SXjK0sx*gInp@pF`W5@KHo ztN|OG4b*WarhebCIE2@69zt)9s*aGkt;+UXN%-^KM`#O(9!x}#-=QDCn#fmC4N*Kw zNj#Fa*AX=pOLE-%e?n4omPdV8EsD1vs6{eiVJ&#YT|>_?k8k>J;{VLM3HrF6j*oVh{;|7>PPGKY8;CMAqEQ9aJ2ogxUl`J zxq8Q-**beg2b@m3s<1-TA9-P$E4`r<#mK3d0$|E29HL%M3H&%_FTpcJ*U|KwJ@+D2DYDN+I4Px-U> z>e+6?Mir*7bW14kMvhx2WgnkxF5DuiU>`Xuba%=+kWP@;O%FUgS*gU3x-(`k@h$V8 zQONyxpZCul5*)2(3Er=0cm%3UV40l~rFU@?_iqqnEF`9o1I1jg z0M8!6z&rTbF&;VI+ID=%un%M`^$F`%<^0u^Q!*Y zzv)f&*y~U1mVYJ+`3>y;x&Sds4x~a%$m@We^{LMgYUs#Dx|PFQO0OeD%I4RJsb2X> z46cR+WjYaLWVDe*k$03Pd#Ga66l`q-;F$D-k16L~zO?uq+g`1qN%pXp5db%y*aku3F(j5fYeV2APNp^cR0WaqND|p7Z)M0q+D-o##AVT zR;6u+ABUABipnspY2QjDI81KL$h`iXz6M(0zQYd80YMj&@^#-Y`y|&p=u`x1wp4a= z{}h#b>`31x7*MB)U3NnO7w)-=U$!-qR74{_zXe9avY_fhkvMCp+?Nl64JU^w$u(%Q z?n0;c2EGA)3UWd8^$rwp?s-i$0B>0eljL_|R(#9o zP~v9`kFK`?$5gHGPN6TiyD_eLfGveJTQm-qM!)lQ!`O$Q4Ou1>Gwm~p>1&nkFxA7J z0=)S{^n|87imWq$%$SG&;h6@yq)_wopT3+0bg{%Kle6p<0_3qPyBl8V=107UBIwbB zRs>i?N@xl0N2t-kOmLhkff%;lUM36{;v%KivzaEu{LQZM5jbO`Pqf2WA_*2PpMp@e zFvRij*?Gm{H3dMXi;4g$f*An%%$!VmCbG^N5zqZbUBU6R`~G!jm0#>=%O55nX0w0$ z8`+;bh6Fy>XU53K3D>CJUK$DSQ3^xQ8*^_&C%^`K*QfJKYqhcsA8XdO^XJd7$3jSP z*}A5uu5RPo1oaJHI%S)ho_>?H9I1x45&vzR^>EoC$Z-Gu%=!$+VUcp!gKNY+K9KmI+jPIIN0lx(f8D+GEW zMkg;^J8y|G8+kBX2zssn83QptL6oW0Wq8HnM~|<@kDs{i0AXQjZjmw)Gggr;rE0t`qEvkEreJAoMMNa z*HsTvZ-zJ>y}tHe>DUuL^lQ3gqVfVcp39Dy}vuql)zuqDf z@_j`*$U`7=BcnbfTh?{vcZqSca&wO1cUYK9%png7Kmh2Q01 z?((Gg&7GfSu_li9&)j^&Iu@^IyX)+wNQ&SNzlro=ug;HQ$F0W?ol?N1{>@a|*-c9S zed|5Y(ktA5!bv>eigdVCjA0I(-ZiVJh~LzTxo2)%FWW}hVHBVwq+-7Fe_)oA_!uN-DtfL?wXzKAEg0p zwiV5lw;u^)fDTv6v+#a#>G!9x%}npe$SW2)TiyZ3Xmzk2a6*8&wpDIlP6qSFw+(}H z*01YE^n%WBZ){#y$*;tGAJzH(vv~U6=!y{RC`lD6N%y1rK>48u*CR`v|*ipa( zBsuqT=<^2XU zKohUM_6h=xB|SbXVDl02SAv^gZD3j|P{p&ZI>_8Pu!ViXwhsN;Chk`iQsi9cXH_D9Sq4P-=%|W2YEVxY^8zx2x5-*J~%kI=qu@C$|tfpoYb{_edXF5 zN884ie1qFht{0$J!ezrW@XWP0h;%CgZJB1_xBOhb6`xAKgk#Y51LMue|85~HMjUIeKhY4Kl@(1uTBez+l#+fAKnqk-=4i}%0c zcW&4Bf8qrPKPEWZrenC_TN6?nlf4Cad#J5>stt>X+)f-=DpF8DZG+1kalmIbC$M@j z7%5;{1(tD+0UT?~k%p^qtC*MBc6jB-oGv3*M<@ijcw*O=W-%WiEzzzbqh7TNLe=_;pTOP+wEI z2M3MlHnC}%OMMdi!w!<$^1UzhGQh3-y$VG@U12Lpx})5R0DjM0P5mS);vLlxJs}CT z1~%DdYjLzCS1YwHzTOYqHZhhYjI`*m^uJM=rj6Vy)9qkSqS~xja&X&x5*yD2sa8S%)X$e=h=yfm8!VCiwH_P-WHYP!zqpq&*^HGpU z<;(cGV#%I8pFI<__zrL4M&GJT<7=13E(tNUGCyskYcM5(b1Z^1Ibz(Xfd*CeH0Vi< z)8_$LZm;jj8StI&G;F|^|6FBMy;`SzAdsS-B5&u3S~f292W|(!09TBk9vbyV*TrHO3ZT@SZmD9O+44z6!j^K9;iQ@2tcq~cT_{$-Fto#DJ z5oSF<^~=0>w-=Y{u9x=z078}3l!SW2_v%7~?A+^S!}#C^IkSKGD`fDlX*3TzSNTD1 zX+sotXidYbQroEYn-Maj<(tcOzvPlps;-+gLF=2;n}>Uot+L~r@4FAC?AB2-f|w-U z&K?_kMqFD#qb&5m-8NtALNLUyOKaX~K8-f#f2l`rWaRtNmfuUP{3}TIQ)x>Wz5urK zHp8ToWIC_kUDBpEv4o6U%7-@qI`x15`VTtQp*{jFw|bT#f??>{gC-5iHZ9v!E_TdX zT|hN1bJ3AEY~Gu~e+e-{wU62t61On{Z>ctnjv*yWcD^_u4X{3@R zGGn%b05C9TuV05>C%XYg;ci!+!!a(1jUrgURBq=}@?NwuFN_hP=+B>=AFAmBM-D^& zY+vQ@Z7ND=Hd=e7086$v4$KL{VFaT3rWf-``#^$>X$hc_!JuB-)>9Qil3v6HA^{;P z_*D&&O`e*8nuOw~R0NyGo|tE+FPt>*P2^nQ7C&6e4a*J~Sb9L2mNE?H?1eEFn4CD_cZ?hC(T|FrXn84|kcURhJ09+b2$S|5u4gFcHNhetA z4@-N9BNiH^gMF#NOo|U~PE^;_beM3x&j_i$IaQEsceoHXazW@EFJZ?R95-8;&<`TV5PgT&&h95aAk1$Yd-_)Nh?(*De>r&k;#! zxu$xrC^~M)(3OkjB3UN~ese&JAUDdYB1XXdq;Kl{GJg*Xb{zGl&|$hSKqSr@);E0i zoFON|BgGwx9I0KvgX)R!nfcyl@~m!2iRN#zb8o~ZzGYNKHGFTv$I^TLc~IYj^cSDZbV|5(=0za3LQl&T zsJr^_yXfET;&A+Jx`q?xs&wn71PqOD7j;yyU2fjwog%I>ejrptX!Q4mzo?AQ6vHTv zSeynqJu${wtlL3!qFgomKRnKufeI@zS4`m|Vx9Z#x`gkqV5Z^6<7CA+O^N0NS0G6) zxH8JnT209FQB19YdCrVxuIZ|(Z`h9kWxzMl$F_5wS?4_rMsoOCp)F&90U9iAk$995 zM8)=)tC~z&kykw7srQJ;o9wLQV|tFho0hP?B4Wgi{$ghx{0Lx7@BcT#3FkwjNlBy5zt$A{S{Uo-u6T&K>ib;i zbS}^2@URr*LAt-L*ek65^Gwd(hXLURD+hRUDudJ));dk5v>^mfsyOo&% zE70M2{1%et5o$)Zc+?=J%N1Jj_KVFVv0Q`pQu8AOv)^VJh&foi*|TxMTv+pKhOJnL zj+hhQLkC?PyJuzJ?7ndkZ2M@h=P}4L@(JK$Y+*GfQ^fTW7o~0`<*~ z(y{w}0U`_r<<>Y#I|hByn!J~aju4ACLC~%!%jd^Xq#;Jzkw`GDFP6H?pC~!`&eyIf zr>SkxXU8z1&;YoQP;8Lx?9{hxislW>sQsVJ*zetGt|B`Oo+NZ0+tYRTJZS{VP<!Rc2BBjAMJcq3k`TtY5w4G-27`z@<$^R zU}U5+wR;Ph@tdYr8*$UDo3n3mtUSp3HCva#iUHvD83QI z9Vmha3ycZsgqV%%?-B{f-m0&wx()VNxJ*c6#_mL_>~rNIN8-R-)NGBK%_j<) z-NZFrT&m#YuD^_O^z~leF|XQ&gaXb76hHd# zGzF<(G$M-Y^R&G62lPQcmMB{Qe(2kzg&eL8Vi1Hq%z_IYW`zLtAq7w$)<)ZxgY#H0 zb#m(UNt*S<2mRB_kF4lSqHcR6H+602B_JCPidf40a+|y4i z!=y_Of?U~bw#))e-(Hsr&?>dU=6bkDszh&?ZZ6txN-o~=(Or1mq+L(8seEb9B996J z>BdZLW`7O`AwSt-Z4(Dqfq8goKR_hlsGRAbvua9aJ{2{al<7I>%A$JDq#G5r z0&+n*jV~W|axq0dOXvnk-P!tsWw>$+#U)V(KlG!%l4~UVOWOZ`$0Q#kFy?FYRH@8J zAL|y)`+4NOC^wmUn!rUzaSC{2wK$*v07mcD8GoJJNRU8<=Wj?s>A#2W%vdr`C+Kt6 z{)7}@O-UPNTnY3gNq&J?$U^JD?_Nv^r4vL6YqpS^3A9QhQYiMon--?Q^zF%`yr$qL zZ|bUs=oghB`8;T8rLJ-pOt4h5tQ?RGK{jNNg~n!kJc&f1Ui%6n{3bB>0G0{>k}+V z1$<*T5x7Xj{j%vHpm3|@`F23`2w@+P1Ly zQ&`qC1Ie%H>}`sjq4jT$`B&~&Y%regPRXpgTZ8snd;4(t{OYzp0x28DO;{<)Kqx!4 z+UF+#WBbXSb;psA@K{7Tr>W{h%{~00R8X4rNNsm>KA93X)gDYOwMJXQUu0jNKTX%n zbJ?=qQ3(2RX&b6IdHTX`M^GnXj=rG*zEVueh2LL`DM?6pH$chzR_tYl(wM3~wux8& zt$yH5?eGO}U-z5|6gN{tH>KYy$18z_g7OvON8CcePs(R^u(=g%;o_CJbmUMs(#J%M z&sb&LHja+YI6&1OiCa8JH%1OT1{n)h?#mPE6h8+RR6fhm=-AKwYn20ikI#a~4Udl9 z+ydV|mpG3z_fVXYQBsZdCES&zVImThPucD&YP!uV2zLO+k0+M z{q{(R-t|ZE(<90nCHr#VVhWq#-LJ8eB2yoNqIZio! zC99j2wAk+VahpOMk4||6?W?$`JmF=)SJZpL^5J&w|Gu#Q|1;tZY%l6gU&^Eay~+hs zl`oWOD)%27-=(9#3l}>B3!AF%UqJ=83p;b$v@K@Q1{J5tppShw=4wqlU&;4PPNhbD zS>2!6Z4y;cRQrOb2TXgpxu+z!uU$sQWWJPDr3jcy*jKa|Zwq zv-L5XD=gXWL^cEvTQ*oHn2#4TIC%j9dI|Sq_`9^p>2@o3I0HyiG$Cc<6GuMS(b#RD z3}+m*0NIbX!F3awNu#a)Cn#r#Bx?<^t2-gn@GqRLu}v~`w;A0^& z%PM_($SbF|)=?J><9zwfP=^%d|1Etv_1ge2v`KjHE1 zA=VVS#r=Z5e=vsk==eSQDYQ2ZXqXo;AlPgHOdtY6o~WkzhlL07$pZ2>4ky$vhqLYQ zjxl2Bhy4bLS-W!OI9xyr+_CZ3^dUik+c!C(g0L!v}n5GG? z)MEOSBu*?quax-9FA!9Cx@)Dp3;_y;6@q^LSd$mUr&?Fwio^i%sA=*iK()2M_EEp1 z1tO`d7xTRi@S0B^4m}G1n=BH$1;yWDR%upX)tp%mdV1FqAS!z}|LwiJ@ylmziaQMu zSNvLC8fe$GnzIjD35c-%MCc)f7!i(#cCsbmziVT51UDO=cM?7}?sPe=Lj8FA56kT- z9UVLJMx4k5`eHU2q^1gEVd4NusV_n()bu$RSsTCHZ>m?E3>S^-j89xyQ!x>WTkQT- z{T9TPb$yPIl`8llfw9fCE-SCJy-Vw~n|q@S;+C0LtYRIHN0EJ5*N^=klxc~L<@$W_ zyazCTFuit>tYrc=pq=M zPRN~L_rf|+Cis+#OG+Z(x}>Q8Zwr*D-&G$v^o+8p(*_A-L!*2GEu0^I*K*>Jf9tU_ zc8|<5PaK>^WI``kDR;#IuYL9Im9kN9#M4Y)(%$n911ZS@|1_ouUF*|x_f9 zk?*x=Rr5Jt?#)DPmY7ep=htUn4Z6R%y1kK8SF-2&FuU#SY@Iy0aET7}IU)m^jjK7M z`Kh6lpT!=7#qm+`NN3n_kDB%3TdO?{wzZ2PSjoj`>p8pe%Z6vi1lQu%MT+m4!Yoyo z{Goz<18ryf+};N=Lr&>gwu`2FX0xtuK;ZJ8y?NUEZf>?nfz8Rv#d@eCoQBcDIynhX^2h5W_r!o~7Y4I;W`Rif^@r zH84Va{1P;CxG4a^FZA-XDDJHo+?kF;{z$;UB5wn+M`0jX4sA>FB1 z^BRsk>{1z0exjbQ@qtLwUK=L_h@x?LnLY7-E*pOlc1D z?oeG^XbQzJ9#KP(~{nYce>mh4VK>@wS( zqo~0mo{}oEoBl+NWZ6ydc>xwkW}WK`{Wt*0Y+kd9GZhv9#SSPX)x9oPMNUa?uMx$_ zvU6~NyBfe4S~q1Svr~MUlV1naDS8^be&u0JFp>)074=0{+wM5wS-b=ilBH_Spm*U% z1;1``TcCIeOvC$EBUOugj&dtLS{A7NWyr)%Np*4lov~he^4SA&w{zr9)b~$& zIpW1$ji1>V;5Xc5m0NoQN@snve%Eo(rRyUged}yPTupGc_(w7#b}fFjUC!3Sd6ljw zZZKej)HBF^cH@#Jr+f2*@3WsSG+{2wWhN~}D=n$ebT~Ze+_by|s>_M$)k- z+_CV8CFBKF$4)K(Y!FCt(%07q;YBK0Li9lagk~)LFJ3IdUVjm0ue5ctvW+qmkJ_F( z>`X;9g9xjNIVC*fkfP6Aa=Simdi#R1JED>7@Qyu!rw8v!5t&0iD_)WH>(WpS?3bT@ z>;!uwuk8P1r*d!!@^)y(WvxWWsT|bwjdJty%L>3x0-;otu;#YJAAB#)LGF>P3(~(L zo2|;Axz~oQ>S$|q+rYS9s)TYc%(;F5KQEdBby zCbP;>uBcC7++ySNZ5?0q7Zt7WeVT&PN($UT%=w`E|T4|A=+m4tkZCT;*S}m zx5Yn|;B@zArfoXY#~_98lYGZ??TsG9H_1BIzQSF*B9wD_^I(2~6koh5npbv=4yuLekk?J#dx%AgFm5+LdG| z6kjQrq^>10Dz`yC5N_9de75c&DuPUYqPD2`Cnl+Ko2is6E`z<)nY}}#;j?&wTPalR z^uBkkNyd#DWvd$k)1PQ~ufXdIVPS4z{Ld3f20yc`eHQxmgj3#!P)k8~_EEWQK=G2+ zBL_D4e!YwguQHFEDm-?yU_5E$lA+_*mOqC7qu?e=rg;wS{6IsR?OJEauF7b*3XKe} zt#Dc0>%|5R)Vya1!ub;!AY7B~x!-d{%j|rd#1}b5tIhv8o!y!yTEbxg|N*% zmpbi!1>^e#b*+TwEhiz%-vbc1gM+54gB!)N{2}V>K^6^gV@p`oHveidXwBM_ ztyrPgn^H|T*~$7Y+VT$c@$x&Rwq%xj>gE(Hr!wq(+D&DpIs`UFtVISSG`7pr0TcKeLZ6kQoDGKQ?ZD^!wU48_1f4CYmzP^5&;p1O+ZNo z>0ubr?=+<9>u{t3gD^g27sDGhR8ITrk6sZ{m`!x*Wu`Y*exrMH+?5N>UBC8d)U*68 zo5@cZ1=+Fxu_K=UwK4wMF#okRZZ}EyZ17j=WmoDF(NM$mmHcK2#Yt{w8NMziYekfg z#nwQSP0);U;4d>QmeAfup5Dz7cQ)+0nGz)8akotE(Uc)G2%n5$aPe?g4kzeYG%9l3 zeK4M<=(>kHO&pgmvXH;9u2r}SA`(|?k}|c;CR@H1_UUQjv}w`#7?Cgg1|^7< zIQg&#%VJEvVQa&an|AD`jpPHWz8G$ZaK7mJI!n_`j0`*T=|>HWB_AznU3AD^a~dY1 zsL}h^zu2$fTv6EPCTpg(K_>;9Z>ga>n-m%<;kz>ox17kz0^OC)`c#0uAO_uPwwrsp1+{bF)je=zi(|w zxmR&nTVIxs!MBK|BxRD#Plt9B&S(NARVomYx)@=#5L% zVb?Iv!k#^&?A*8bg9egU`B=Ltzn@)3!_O!JH4hEh`dAwTBuTs;Q& zTc9>qeyvUR_IpPJ-=;4#^?1Ig?S&epz85E)k} z^J!cV&B#-KM5^Jb;d3#P+amI>>ha;fYYE9eHp*qZhIEYKvK?jDpjm1!tpZn)Wt#2< zQHC`UNE!C^`bYrMK|z)Qz;AM~&%Z|!61);pB3ibL;XCGTq0)BzVjpl(WAmK z4OGoKw@B4($#BuiL}Trm_AkzOovj>XORzs>f-OP&eLEtrQF5n_i<+{GFK}t~(vFwk z5R?oO6^lE5HpzQ4y9+)}8Ce9+nr(&+S|yQ(_dfFVW{WE?b(^R8xZ6dA0Z-g-b#>~E z{c{tL3-dU$2eM#M|7dW=J69ZkZdSh@#74izryd`-R1Zl{m}(+9M5TguGMOsUt-1nHTNpBc-K^k-?dr`p8{)0 zTZ@95&wZ^(LC4^sA#6T)VRqr(3f10<`j(Dy=b|2?ofbFm)63Io>Ez{oO#jBjqk3Yw zus6eIZf>b6C0(VOhk-=&-3|$5pTvLNJNFlopRN?Be`l3F--6)`Blb@aG{>bgocu^~ zggA~9>xwVsj#cqXg`RJnO)uCu34SjE0_lQINuW`ZLWHJF z5>uWTNTJF6Da>hHA7H(uTO42wfi%Y2ZGflZfXYq(XQd07<}kj8@-Q!Y4s|Nx9&X1h z!XE6+`9I`*e9CgX3%E8OUTK5+okr&-9ULer)_*S6Y2eVykkP~L-7@!^OTqBA8y~H@ z*{e^c8#h-=9P$E+yVF))OB_86-{8MJXmZx$`(OPL1=D?SSq#R3~s4zU@CcZ$s4C#uQG3a{`ND7AkhkBue1ZqU+ z(lKoEQ$4_Y@7{yU)ebRbSal>LBwds(;A5-QToO3V#mh$ql!XTcxtt#!TIKXQ%yqSN zQFN1Y)EL zE@?^^CF`ily~(?Vk5|80TBcQ^U>IC7r)CLIZ~Df9iC=gYHF(msbcxgH0uTMmd42-Jv!O6Y}fz+90G- zZrqk=*EWCL<>Rcl-A{G-U^|gCBO2iP@0-g5>pSSREDc4?K6%(VLu&ag{1Lodh>5Dt z6gW8#e&)iJqL4oJ%hq94_o4K&3E_(d*wP)=C+<}L8(FZ40n&6W)4H=CS=T+pwEYeW z$kfF`?)bcJ!SR%{67qNvlx{Q=onCU}F=zD=5?Wa6ojg;tUMhM-3^7{!!zYn3K5x*w z_!1R;Z;E|kg(~Cv$D3#oU$A4iUAma2j0&4-f_VjEERWZ{dGUNYw=m@EqF#Lb9X*0O z{L}=3!N|x6b~8C)Frk#<9SO`p*|KeCFN;J_exC9}rRY=REy>jyD>a8KJhtK!hm>NS zyj>%q*K1MDuB!sObjx<%2M89hKJ8)_95X;YP1)UojMP4noj$`UeHLH9ihi}kss1TE z0dfcZBl1gHQ#^M|?%6M_bhq6Qd+b-J<~KQ}yGDdzy_p?PW?BfzkkmI-XZ(MRmN+ts z9X;(LN16v9x`^b)4T-_uPy%9N|EqfK4lVHx= zjY;y$4FH^nZ+@~4<>VcI@8fQn%cq@nQ3mtNjA4Nsi{DR2I$G;rl(V8!#{Q;#P^aS{YlZP>OiqSg-6yqv7GtoNO>1mO-200f?E4VF9_dVY z=7?SX&KBEpB^np(^!v-ZHt1umJ|TNsPqGH?7Rf;a-uW-RGb6kTFPPm;xMSB4E$Eyz z)UEz<(s&!aVyAK`TIFQ#?134}deD7G^VEqru4Z=a8YdIz;6N(Z9IoWMLzV%|R7Q9HL(^w}L0^*Lcz$z7A#l~9cA6=%|NXG# zYSHV0n#Qk4Q>AL(j<3-~EGC-^y!yoH6SJjg+{LB^ zL3WRV{-bA};D#So?64(|W0jlV)cX8nwMyON(mC3DhnWEODr;mM{LW9n)lj!L_(<{K z&P*dxHz)kzF95^>8|_Dam-0i=Kf{#YFYmu4oN!go=;Y7>ccb!O*8cIy<-+ZMwer;C zwtAq9N#>mxefU~CxiZst(UKtEY)+gAM!L z43(-Q{D7K$;o%Cs@hE`zIkMmDbNv2_$34ewA4o~3z9D1%Q)wGoaM5=27MlyLUn?w0 z-}igx7E;zYXp^GoR2SDzNdJ!-@XzM_@9j9Dy@F=JC5L=TL@VttbJ21-_WAbjD_|vj zV0A2cIuRzz3i7_j~$7exeX$eFCO_Rw73hZt0?QKk4 zUHe$M;MlK08m(dTFY{}?LH!A}B#_lrC&CE+sl2R>20N+7S#6!y1}tx8M&BRNf-TbQ zp2zj(wUA0?YMt=9jmr4~k8M06XnS^6A)>p4cHw2f#wlsx+s~O^c^MZpwGM2Qw6?FT-@M$fJ*yj` zz4t&CdX2tC)}{)dvC%R{VkBFMhq*pCdY@R#Ivf%e?4|!IE{DPSc*rLs$r}9ffa3is`h4)eb7_Ceo)T(F**xOy0#pXyFDMxs*?jcJ7YOKTx;r4y;x@9Li~R` z?ZbVn6{e;hZVCKQDm!bhhaaeEkG}(ly{V;B9_z9;^@GsYVZZ5jX)B((7);7cK4g~) z$CNC>mV6gAWpC;(pxqk15Y}O{caCc*psG9DyJ+-Rr_g+flf6ngRdoN5nYM4}L6~`C ziG~u4De-`d|0E@KClbxZxh<&es}j+r5M!dyYQ$OY*)+#q_kCPWMYY+2CeNtO>5{9@ z_$}Mlq2iM7fM>z}yZ(yn;hSIbQnbV4 zT+O15?;MVVAM1CsY0hxUz7&fIorbV zm9b!v$g|>v@ZEji_{(H6?jyYc)oVxte0_0R&LwC72JPq-^vyjTzZ3JA^M_u8{ONbr zF$|=$wTxEPxL$+I`0j7zTso-VX{(Q$+uP6`gkEFjAfJ7!o?jDPG?Wv<}J{iItk9n%*PC?y?%4k zc9gRC!2afpwwd+3LXz`p_TZaDs@IL7*I;U^-_-Nouj#qzzlq~=m+$3zCdiEr@owvV z@!hU_eLYY`XxxNhEu7?IfF|4*`@?gK^-KKyx3KPah5*$ZiQYmRDkWGqSF~3L2lS2p zJd#iqjc@ST^eGy)Uc+pK@2A>6%4`Z_=g;S%JzmWC|0I&I{zfbP1K8uz7HJgB;Hx)9 zSf-~nEKA)x8RMhw8aAybmxy=Ckj{SeO^oMD-+EzdmNM1>eQy`jqfd76E-xXmVd;d2bIz>FsXWmCiqt4}?dux^`4l5F@3SIb;L=q^xxxLV`##e96hy!EB}F>%-QX}s#h z6eAwmkT>>YeIdR{AJBfgEwgx40bj8h2FE7+q3_tt_@fyim4oZ_W+vUcVCM+RBk#prayp+!wNk}ciU$S4G{0?4{(~-S(Q}QSUX>V|I-RM7 z3T_ep&|-2Y+A(^K?-uTR{b0f;K1gg8chE9fc{ohQS<_t8^~;W$53Ok8>TXNBNT<wQqyoH(d&#zng0 zc#9ZC+ll^{>m?|Yp6(PuDS0P;B}plK%=1{iQ?sP{9d)1MAJKi=C5{vefR!677xlTW zSl~)knJj#>vPYtPFzKEHG;ELbSTx_(ul->WRA;mn9D8?z8zpCqKk@GU>Q?C+dH(ff`W74yY5B=1N~UjHwmK9SH*Ff zLdfp1IbsV4hAHH8ZLJh*ZU>JtZUg;}#Ff6h?a1dJ=}Zd1}2O<;*u#csOv`lD*$(oj<*oKP_0sr(pSp26li|mU*5D z7*H_=<}4wSWud(ay(9(Ql!vB<1*28zBujgbu1|TaA-6-YOz{O{%F=C!9ckC8L=oU{ znKnR$`F^As=FYzRWy))n65xzyuslS!6^q#E+?B8L!4S+{P6gI{g5hP4Ku?682x5w( z@EwS_>=`i6&2|o~^(ze*dZk~TB8Q)$+dI*~2IJ3d8@Cld#EFO5P5TIN;$yr0Qd18W zj5RkB&Es<=mrsu=hq>KIw53EyaxZEjLLBe?ee1ul9sMMcqWc+ps9PwOFg zt;X0MydCTWy=U9)#TRzmu6oWT4(Qac4AVRj{0xhDaesd@f5`bOuQ;1M(m}g`Po^h# zjFO)1o~d6DzWgW4|L>K3OKkpw%H%Ew%o9b^2TA|*QS&t#BNUd5(DWxJo*sN8jwO+o)4G4W4VtTO>_0|I5i z6*`;)nsJsq#}f-sH+4hqfWlid2*;JV^AW?51m3{Gn`r(zBa~i}0+S89@$T$4)4V`v zY8PuvVdgIaq_F)m)^w@)j`+<3;q54aufmXayh?M>vxa?bL{(cu@JkB zyZU8dmA$f5Eg(M>`asBrUux`=zISQM*T*F27d!L=_F6-vyQy4HNlB^M$2(gzQsgN? zhDvpltd)7hGsnBb@4+H}Wp158C}{J+x9Kb}-r&BnNWJ64fKD|IW1dEVcFYIZv!YG4 z*m<_d@Y#1-JB9jyY82zUvV6b>9JD0s48b02+^##TdivREJR-pAUwK`S&;a@)j34U> zdCE4MIHoO;>4R`(>aL;FN#XEffKx0gOCT?g&8d){gJIfnt*#sbUi-%|2Yflf0J~YXDng2Oo zI6P_fgqmYscln^U@4IK^&;mh?27RBZ?;*DM(U6DlR-)=*C*|bD$m7%oCz}w; z{NlXf>0e&T3VCTZi5Z1drBWxaN2xrMfUfOY@t13`M61;cgQ~ zX%r8w6(f?8YD$%6f@l4WP2m~&4p)Bo~%AKwicnwVPFMl1@V zh7m$!SqPBs9WzIkRQCuz@!PD4*IQXerBnt8xl3IT^Lbs@C$ykew+~PkBcR2@2ey(n zUEBJ>FBi_sb(I#=yufo|BE7d`gavg6Gysf5Dv^BRfBT5~Ky0sdD2971AblZLT4VJ4 z#1ncUN8_7^FMCnMnq^`v?|WGCbUzoC4R*|&<0|VmQXw=W?Sm{Lo6C}QWW;H78RFl@ z%_h>SN`fKp@AMZ57R@m|VNqcQ%Z_srpW@mj&xGMy@xxK?DlQn>2MzQ-0)~~l*a^kO zt)UTlwdA}zL4P51bra`R1Uyr*4=JcPH9*T6(7ioLRTotxKUUy%fmcV&kx-e+)Yp^O zp48=eVAmh^ksz%rOQWxeF<1#b`9p`%=sSs>uzrI}G2r7hH(fJ9c1pzfO^am!an70G z_W3^GXKzPIW(H=U7cRkQ`rz!L+xwYFtCCEUV5gh>a4!5UoKy z3By6K62YKADk*Gsy?JHE=aYng>K&~|SQ34F(Qo+`hjZ^$IJo#E)d=3syii$yJ`2b0 z(E__6oXN@I79}ve%-B}j9FTG9Reuj6x3n@sd2s~-{lu)aI&16NEn;1F6l%Bt(7Sm; z@FQH|qXneM?gGmP5s$aUEykY}u=EC36`P~i`c9@rvv%6+6kNBmwqInbi1FRO3^B%r z!1lOWPnEb!-lfQdwNhCmWwnQ<_+CJCvTn|z$!Yqd09TBm&B#|M@1b(#u$aioo;g8Lr zs6J&(aJ}W-@GY6F?zqw1L^4eje&<)H^%qCYtXMJSLsPG=0n3{0J`Fkt$<-kzn=KQ+ z7g=RzN*W*(0W|HS+TvAgJ>|C?;`T`l%aJV6qE78U$}7dGJ{%cNZnE;nr@FC1|x zM&Gi~2pA>c>ucr+11*7@$NTEGbQlH~$0}r8HgHvo89~0lEbZtL(;O2AM-cbt3AIn3 zGP25lZ-FC_0r@a;X56EXkHGR7*(YJSuVsoyUG|X{03A1Rad2HNqhxR=Z*btEUi;>e z5yNTt+NqbBVQ7?*;3O5_N-6zKd7nfdL5D65`YTcY>F})emzJ&`y(($j$y<}-_s3_d z-`h^9bg)hF%dp%@_VceLFQfWOUKn|i1{b&;BVMKGwG(MaNuQo=|9oi>kMTwp=!&QbFf9>^$YQpfC>6F#M+R8xT#&SWQUImU^ zgs3~M<>rFh*$v|Y@Uo*Q5&D3uM_D;yDG85gty~>&#QCVhoN3i!Qq*oFi70#67tJ5~ z;=JWxhn7REQz?!OuU)sYwsFSPCqfOgAv|cN;m_&?|18hY@5?jHQARIn*B7&gM)Eg$ zo2YclYa5%EA9Ru7a-!=dgQ+{$JaSjHwiPjS1-{9L?I}ZY(kJ zhV?HLv5He=0XiY65AJ87c(}Rg{}C7D@ZYo;6vKk*Io#rD29!Uq0psG=bwr$MfbciQ zMi-=H^6u1&$|byoSjoxlsOMR8L}#I9l$En-iHz1|Aw~%bp_<)%C*wi(P2V3L6T%T- zCdlUTJfN@VLieEZdMQ9eQ~9aPU#Fy&2t%>qO-f~m97%_6DtQ`e*Mk-IsojCrVRz~} zV2LD%mt1#FwD1r1`&YWFcUeydczlymU(c}sI+9`7=u+@FI5f1jeP7TQabLc?M9yS~ z5m|O8r`*7F{3Q8`R}WDJ~V$2A=ByPjPmU{GMpXuMV=d?}e3=W#i7ZFzX(|ZC90JOma!MH9|U_ ze3K_u$~CK^$wwi6EjCM)b@=B=50P-u!~YxguL`o}C-$HTnG1Bg_S)om;DW{F>pqRA z>muP~zVx3yebSC?inuMCQH*Q-Ez%;fyiY2%$mUMot5nOfez?+T60_Xq1y6S=QIv+Q z^rTbhB~-fH(!dL~IxoE&z|iv@VqN*|G{mRZ!V&!R`DTt%(%~HL_xwxEOiU~@wiGs& zjh+Ej>~Cw>?I4s%;aNGIFvhQrxX*0UU*ig3pk!R-!+z?Kc(KG>BjK4bE}&v!)n0=? zVyv0wRm4EMWoV=&SQwr#oYz}^N~!uORFC$y%Qk-Hid=)gBi-5bJ4pYHWSAWKY-Fkb zNh7PZD+&5f=}I;{?-14-C=TxD8VOfR{-mgNyt;;Nr``X_SL~GM8u8R6#>&x)Z{6?9 zO5e@p&Qt;#Ap?mrA}x%Z__p)b*RHs6Meuu9<$J3s6(B-{99LoOcdiEOyDX`GfA{$Cy!;^3XfKlKNZ2C^u@{)oUQ>6MvJc3{+%?7sps0 z6>ub=o#5tmN^^*6F41BZ*}U7;`n!gODaWGsab;lO?Xl0Ov5m*wt7lO`n)mDKj3Ysl z)HLx#IukkJoh6e`c{)c7+PApoB6%Z8$0rQP`nfsA6^BIiY^64SdT$Cjn@9J=oDHc{ zRQAO?e9VHz^v8cMZ0`$6@HJX-;V0$INA9F3g!ZU;GX12@p2h}=WQ|N>Nxq)ueTU(( z{LjUMPqPP}7LKQlFL%FkMA^F?-((2vbMfS?%$gJ=yD>)CM#QZ? zqw63&qxeMHR!;cAENX*VxaCv~lll}o(5(t6t0>DlXYrgazq-SdCCioXx~-_6Cd zD|b}mavn?G;nuA6e#9)gZO&sWZO0@@eAp;?ES7*ufOrGnPsA5;&ppvx~o@wm&+0C@5`$Q2k|~DR+4w|MEc4duP_~-5uy)8zOPbR+gf7$F##s<)1HK< z#EnndH-al1YNZ_J_%%x({<8RO$(|kwQ`|#y?rLbvOYkP7eK390l_wQD<!CA6N5dJPGBmtv%V=*SRv zWF8g483in^GRw%=#?NbJAO$zkvl3ko7algZ7x!X2V0iGaHAR!^)550Zf zSdf+MF65zsa_5r24Tz2*|H)DB#fJ9OQCg_=c9dgoX>!yYor#tzb%#7Z_N+sd)qq&k z_96N#l8pknS2JXlmsmx>Nyc%wf0+k^@8e3ZezgqcNN~Jp|XoJgxvQT>?OYWtkXrpwyr2Q%B$V9}N-W8Fd9s;#*>Nv`FyZehZ zk4|?QS)yapQhS2RB@ToCPp8#1hk^d(a>OA!Uqj=M7_Rpn4QOV9bJu=5@qhzzq%&1S z1{v8pPbMK8j>&yzk?#ssl~|x2<%t#1Ly@PutqkymqPVu22coT^S!;n%iRvJjeV&wY zrr#ig_H;5-iD;24E|L+sc1rW>^a1gd*qr6cWkYjp#Xjp6V-by%ukoA_@dBR40{c2_ z-u?Nt6BFg=n|T%~Q(y{d-nPNAevjXB+jfRj)7pC%hN^Z%z>|B+Y2Hi$lhHCF`8wna zcPGS(spXX2eLJ?TQ4|}JgLmDzFn(F_J~vi+MlS20aBoC@@JiyNWmjoR1^l05LfZjC z1S%}X1^y8N`{cm@B{-m>`2wzdqRL1WeLo#Jac8kqyw8O*o@b?@#490G$oitAUBYht z9gxMWJ8Is+(4Y=IFinWe%H{K3F#Ens*-2Fx^)Y&R+Zu#swd4A{T8&n`4B}-7#5F&) zm8q>?h1K5iY-+CCBD9xnRLmCZIP|Owa_)JzYs>{uh!R*F_ znd0@(ON!-XKB1N+yRC^^P{3y%fxf8HYiqv+?-v-UPfpgNpR6d?M&`4RoNXr)yUwy@ zf~6S*)*@bV2x+P8c*tg>(KIbP^H$ z(fR6<-HQJ2U^U{+TYpRY{zifS0usC_2vMY0SIwh*>17zh;yFdu;~ZO6(SSa~a+%BqT@Lu!(;KaKfiRyVi$;l%T zR04pYhHC@XEXmO%VRic#*Rlj zBjX>0Mzr;!pM0OtT}@t!a7fCj3^0CIL#{#4ikG;$mmq!h;(o1ig>LMI#1-!7nXU-T zK0LmK6E$3m@yGM^CDJcLO8G(;rdjq+6HS-wN9s^$}ykxTX!mpy&P6Qh;je>glrj`bg90oG>fkz$T{E9ZjX{|CYPANnB* zxU~QO^aFmtj0J`%^)q8Uis92Md(cYaBjkw>rSd6RL;W`QK~8Nx3cz~OBY&){sqk`D z$tL>B>1W2US$MEW51?7&TCuT}-8>VMPz=%a=Y=|i<1?zut~ajxfzCoI|B1(%Z8oSd zQ${(!MA1q8-nOIlc^icIExylnCniLU!HtdPmwk#usk(`&KUbK;Wr$G%B`RX@jpN_aNg{x1HM5JS4pN`{fE zhFY~s+|ei?<2I+m^(pL}BuYSmQ{K_# zx`(5r;Ae^_=T4DW%V)EJq+P;&d!GAgbR0-Na6#Ck9S3+2^2WOiS#h^>R<7Q6$oSr9 z)mfJw{%h^R5oQX}O)FVPT{yRBYor&4b+TV8U3BBx_DF*b7d6p}?3HhSjy48uT4{v* zk~m3L%wcwtSba_Ir8H;{%5gqLr^^qw^UM3vYHWhwH{=M5iWhK7nS8tF715bG$^jRH z;|TK|%oIOlLgRAnCP5{Yqm^t+TeABFljj!{k9wwRp;A|ngc-gTcoHD$(gCC&NO^ zJ-pG<4PoWWc=V0y`X)#cd}B;30=|$^IvXQYQad7cDF5C=^~a~zPGm1(PQs{v$aLoY z+?*gf(kE$8NA4fl<&kp(}`LA#b)Lj2ss(xrQ{XH&Bt*fg()CEw7-Z<+`Ka;1UZ`|60 za5BkW^9ZRP720Ixz@gz`LrY6#!B1DQ@4{&sA!J2zZQcofmAY0o{3DKg6Q*88Z8QUc z+j(hv)0Jelzf{J}dnqtXIB1c;ylHW9svo(3+Ds!L+GwTkvT6>8 zHKM3C=mC%TL7TGCEL$(vl-nJoM9GsECi6*?AAIA^$6=T*w9)kw<$dJz%)okW-Cnp_ zW|qSM+k0pq{tjJz&J}cfp;VUGE`YK>Rfp-}TM%;gREY{l$vX0yHctjsbt{s9D$wK= zB_Dx@?IjO4)#k_CLt8z}&&r@a| zPDkwHsJbY>Y@#PwwdgKC#O+zVUvXd?-6h&0>$DZM>O7l{f4B1E zyvU0r{<9-EIy%au4TUNe3e}gBl(_ttNkIs*$NHm;O2jDg9t3GhZ}f9iz(C^DPfSJ9hlqHp&Ps zC_|k7a81wqhaweRasOd);B@^5Jp5Z4>)*hEg9YXWkGKDGR6W+fs!x1MrcqdC{JA3s9yC53^>Pqour83b@S!9qC{Wu`PEfOObs$|Bkas!Zaze9ydMDK&S%s@@fO9dsCw3YqvlxqX zB{1PZ1`PX-XN2sbnT8?@QYFKUPLr3m@yPwbAA}qy+pKp#8V@td7%{J`+jH56V5bbX z*x*7;!N3jX-}Aegxl-t|YR|Mi`DWq2&)47M&vErsL-Ng7By+zIKQM zZNpW3$*$!VPNh^xjo)cehoq3q5vL7_1oe6a+2J`pVC^5nX1LwNJ;l*1R$3B0NMv-oKjwKmX+q(9{ExnNymKsk6TreCCIj?|8 zZG$VW_06<$EFB7yo&}ueeRiU>G$yDxe$f?>`)pqjqk2a9f;OrZ(+Fe9l}UAFl^gKOv( zmqcC%rq|}Agxel-@DopOyD4{`-*fbi$JD-Nec+^6>D|KGP|%~4wHvS?>Hnl1g9E%} z4_#xBqFqu)M3nX{_uC}z0)ovqgF&Nhu2MGHNsd_1-E9tgx zp{13`|L)TNb3wu%{(Yzj%lNjDmF!>`X4T}PF61ngFM9?2XoKBDtmJaESni|?Ke($L z92|1`U-mxs;a}Kd$M^s92=Lmu9~4Sweo|o1@~ zFmF>fv=f@!LToI>#aHI$Jv(k{PS^f;2I$OX+2C49`Igq+~S1p0)8evV^XYc3Gnbu=kR8zxlA8cl zk1v1E=~GsZsUs*M;t>UC(?j|3c{nA3v!$j-CUpv%vjz2+YFomU#j6T+;xh8sx|Wg@N=-p0eP)wkaHTvHQe$g{Xs zcF0@Jl4nkG?<2gKdU+{{UEgSUFTE~i`piZG%9P{IJBzK)UeA3)D!44NuFO*9@ZGVU zVF1)NZPAx6bYIMjthl(i&FS1HcXMu#t&2oYZe(i#Z zf~O}6RMJ;@tmE^THF0ZMEY4* zJdP|;r)6jCZB&*i^;TysyYtq)7m!Nd6VM3iQGd7l;#O>K%ot`o3@{@3Yd&wx6jjpCm6bmR24d|r=?S&RP!YZ& z3DeK!&D@bi_WK_P4T3Y+P&oPAaJ^jR^?F#voZYU#mj$O(Dn2Unku< z+PD-d(S(k%tKFuK4`*ooy%t@NQW_I?Hb&p+lYxEQ!hIh@g^!?07|eK{#=8<9=ytuP z*B*-|y1?LHi86|7KAiKpKvz&g z#Fo|>+M%BVid0p?p~eY~ovg@g0o`e}GUV9D)M)5SVK5;4>L8P~o;Ba|ips+=WFTpY zVRACLMW%#C^K{+7YGdupME8*HRKE0VD(s;vjuN$<_*JXbVACj`{||$;*PUqouhFN(^EXC7#@9%D<@spGl#+XwQc4cEwaojo_$h@TKY&8Vs6_Kns#^Z zv$3h^fN1!f9DbjLI=aD0*)NkQkBBX|TDjlvEJ-OV{9fJ&^fLR$Tl;lqM;V>Q6TZIq z-*7@>vlh(E7ND)mIGaB6Kl}5^+wfsD1KiXJS#Ery)J*!KP|inJg=Mg7-j0_5XNL(`AxcL+wPpH3YPso9BcCgUF8^;xYw24)N>%I6Du0F7i4&5eU*5Fjhu4VI6 z$FJcF%{6d|U!9}L>%B5;6!x@yIMsqAlQhdPvh6t+f#hnjz)d6t2tkmQnBX0_ktD;r zLT65ES_OrQ%hsvBMp5t+o?FGw@8kCk&8g6Td=wYG_QfhLgTSktq&UMG#M(F>CW;rh z8?AzMRxa-Z{Up&SYwd!zefI{=87ZCX{x3d|^aC<-cIJz8IK2zTH`c(#0yN_gdZ>;` z-Ct6K>D6i~uu`3AIz$$F%EdJABXA(!A#ZJaz|Ajr<>Xul=j%K9qMPtQ{wDkj+iiSk zKEHQe2B$>CWj~=SycP)Uqdt#@6^|{^&pVx>Pqz~5T6*hFu2X91M}If@hCaF5_$4p( zak2kPp*+`(!QuVpI+J-9j~_qijw#zc*3V+dg?Cc<@LdKKN7+D95Ah$qSwu=9K;zo= z-NJF5Qqmg`BJ|wtwSP%o7iRH}l=gsPb!N=%}79m=A$$%k$1mL+=dQ(N8BjaI}`P=+^y+sh<^)yW3ts&v8QyPjg z6wJ;a@F^wyCu_PQ8Tm=?5OhCO*B&35ZNeL@C@oT;X3EHoEHe+lu6t*FB6zNq>G8p9 zZ3&=rY7WdI9T^}S0rA1+#M$0{-LBbw94Cnn{pYL*X6cWl5D2pBS2GqOT;a0IRI9vx zxb*dOLp1Bu@r+|-VxJ&Vr|hO;51;u>vJt*-8iC4)viQA3E5wjYuKqw!u>Jo|$bWwi zb@;zZt^(y{sA{_?^$Ej>wnRLCmV)4%R;v3K(OdFD3yZ4Df z9J|lqvwZqOsnFF?i#d4!;8I9W4?!N4MXkcUJ*DK;+#eS}`3T0u)@0XL3!_pjJ_S_e zH_FH{SkW_LQk{a<#lC8|x3!?Mh^mF_8w3ApebK`)s_RcaZ1NroH4w#S!I;Kg z%0=Aso2&!~`72prWOJ(BOY3qoN#Y*;N~P(6OB%$g{Cjr~)RiAL_!E^FPx5!UTz->= zdN+Jw{FkexEBbMEl{1MN4#ssqw-9;;i+)J1TYb^Pe&l)b3jO6XTNK#;H42H#C>#2B z#pC$ad(5%fv?Th1CF_2UZ(D;Z2ef5i5dpsu;m)bWSyP<$!BkyJRplEYYf?6yl*2z| zLx;O`!~-*#{9YYg__~8M2^cCd41DAq#RvHlOsl1z+iwHL{mOM^;>%IJ*24x^n^#Bu ziLYs*T+(dv7BXA@bjS&q8rr>>(6XaLnW{1(r|SH( z8%K~14tqxhoD<6XQrr)u(~N68Ml%) z^^&O?5qY@8@Zo-zH-fUz?Z<~f`mNL)-V^W^sVDpn?{+@RDHGJKw)Pt=xNBu&;VZ`y zhN9>dnflEcyw`9~E%Qq4?!C8#?$>9J7B*$RA6dEYN$8uFs2H3HZmf*v%qKHBP2qI3 z&^8F#yeq6Cze95TNp2O9T9|H zWFK!0O}RnIOv7jIc=Ml_jDLYa-2WZ64+H-T%#pmkSPDl=gW9n2affSeVd+mRVYru? zt|7C1DC^(&^C_b4CxUZ=F)Bidtx-J052%2=h|79kr>DavJ~qnma)65( z4=kM)9$&9ITG|j+@krJ8+Zx-@X7d1x zmRVyJ@gpi3Q-}5{xu4cp-e<>2PKY9crwHJ;P(A7h-)nR)JJb3W!?Rc_bXRMZhPQ=x z7w}bUK+AInG%85GyC^a1*M-O_&?jCb1xV@?!(cf*k<7vRBH9`!@m^Z2b1zBqi>Ve5)yt{k4?Lp0H9uW?^WrfDY`F=ceDsq1^zBo}sIds% z=W{>1^(v4{yVo^qw>jIAT&o>9g8U{BRp6`ArytU9*cRSwp`$4`G6HAh?A4Nw06DQn zfLD2-+TL?ymRyCE9?0y>t>ka(U-nMspNGCr+iz_-SA7huwD0S*!x-SUx0%eR2=s7P zRmFu$U&MnjUXiVDWeqfm^bkI>5<>+lrE87}L${-d_9ZUXAD-WHY6OrsBqY-3xYS0J zClC#OapH@Z2d?^;iRc?uz&R=@*2m{OOc}`F)1R-WUu6^2@{@WxURK#?8C&FvbvFqc zU&z9t{o6v1q~|E))cw`9fbk9+ICwcrYY;D~EqPs-+UZi<<| zx;jy-=z74@7DAO{QMUJBeDmaT!HqXI#MU22GpHSMD+EA`z(T+$T}UPOGwR&N|1VbA zEOc&q`yblwzsVJTYT`QSUwNJu&&YmI#P(^8nmpfxweqKjE8|!wNeT?yF&BZvt5d&o zx|u8nAT1>}B%Y11qtpy~U|QKSnzT7u)hZ5b4g9_1tUfs2@hO#_##O+mgJvw&H`TEa zh*MLWvQAH&PoVK0bS3Aafq>KZ2dTC0Z-rS~1+G5H_@WIR6p^rBToBl^LLx*zTXlQnK{6hgU zlaipHz=8z^8Wm-(G)~6ITtof_|AS_!zlBKoJ*`eIE?%d+R}of@Q8^{Dl(GwRR^F?O z;^fz{P0yXnURiX9ZVoLbZL~suljRU@2DWQZwR78zKG1C$SS#At@lakGkhW_#o*7R5 zJv4D@IplPzY^v)L1EW7EXW`gkA{3H+0RH*K;Z6ik`cIGdZOMmWIkm_3P~+2`^2tl* z6}xuyy2rT!g$Vw@3C>#sM>w3b?QbhyldmcCV{<;s_nN1|eM0lRlgbj}32q1(WLeEE zV(GBiwHUY3xLibc68Afz(3N77zoOjs4jxn5E#{4ZxVZkD&1<3kahR(|-9(e?HU0y7kD5`QMJ4?0ElEyr`EqH3iqD%DPZ>-|>`U^*;tpnG3Pa2uJ)!%Juj6e>Vsc)ECaR027xK zTYzTKEi5cmb`%EuMJ=#=RHCV;o91={7vzF(J`KEz{eTvRStXiot}*J$s2lIh2hHO; zwuJ%T8AB1Tn*YGOF3J8<1EuTYQ{GpfC~!ZVXqN6`468!>ErV90_|maydzBMQ%b*<9 zCM#i}yb?BgX!DEPN%&(}?9ew~EyLUUdGiGydcjZWJh=y2-)RaVt;Q}bF}ktZ+0f4L zcwxDvxuyM4GblC=C=J0<{;$VL_FyxP^u_eyRgQ@N5GQkuZuN=OV4HDqhUknBdwecv z%ZqcgB*6~=I!K=Q_k1b*)n@qaetZic0ybtm6Kg=+LpOGi0hD|5j>YP=GOD4bh)L5U zr9?h_ZaknD5u}3;5-ffzb{dhfN|n%nJjS2Wg+E>0@1FAWCJPn4kp=veR=`I{P}*eWe!fl|AO%Mp7#f#E(EU1K zqh8jkFedPxeIHVM`&OlsPWuiO~rk+`eL|>!e-IeO31bFBud?YP-;4V)*ekr@< z&1(|)8`{i@R{Yy!<<50!{4Y>$iEGt%0f+*Q?qxewxsiv|ze&||$2+U!<-K8bc-!We znODN^Nb2H@3wOrXKDpBMTcnSef8~<$8b7N#imjFWa`nRnCNHur@lR#1Q`Mr?YS^Cr zI!*qkTK=nU_~#%0f(kd*|Le@+*OsFhKCY!K3WBZxy;z8$!W#wbw2B;9gBemq?OK?T z>Mu(uL!9*l^R8kG(%!#fR%MzMpibLDk>dB=ZnOyuUJ-4;q zIt^-d{tf;Q7w>F0%x3%gy!U*iTLlO66fpV5(IS!G2i?*N1YNgu{%o9u}*3yv#_uFlr?E~Ns7IqcF}L=4KM@X*aUBm+`LFAuOK_YZINg`#oWQA zUoT7cPF%W%@P~(^7D7RCEqByK(90EmnbglQc!dxA?+J#6bMmI8M>m;H-}&%p)?Q(r z0>!~&s!(68KoFb}VBxnk-HqLWJJG(VJ;-}lw5TUm+s+DWtgoMU{MrisS8m%Xo)I~%uH^eT15KNT?j+^9eYn$gN5w8wp zTByohD_N2}sBdcE?ni=cI?aCR0_t6Oyr|?sz|WM&*yQ)uLY1O~+-Vj2P`V!1J(iTt zLUP^Xb~o*NyIYbH8g97or^Z!IpL>=&$N&gGcXwLcqg|FU6@&cAb)HVnzypEKzlZjp3;%zSu>S)4K^?%5 zvzCT>N-o>ed5T-j3%8=~wccnr%LG-Dj=|urXN%_IJFt@Q$D$z`B}j8FA;)+UFUE__ zjPdL1dUM#**>(nZvGQW^v5&w<+dOURRz)ftbwRS9#Z!I`P^UDwJtR8b)f;8@DKLX& zC8!0P(FV)_N*4xqY!kc7pZM!#YraeIDu9(NSRpn?KeNgq5jde9^ZCiOS0i{K0A+-; z=1F9h{lucicsUpN+&DCSl;it285;I;p9f{}_Ev~KJhL1CHDZd}5f3zJ`&9CF2u=Ud zos*?1YS7}uvrPqe{#NXmRHA{)5ZVsVl_777h@CdyD#801C4+eY@!T{*VHN^Fr#JMo zC^me#tFU#lMl;BcZF$JAdG2hKUfR7A7zXG`tOyg~BBf-uIHg^;A{DQJ`)^wWuTEn} ztV-@JKyr0T=qqRyAbPZlq5w>$UIj!=wWFEmtZmBSk1_~0YJiY7kHa>}Vh?x$rFC1< zFu(R5%rlD~+`vb;lu@YiZ}GvS1mmX~V0w)1Q-wy(k8cEDw$h*EC(J^n(QN*dtVf6F zzcJ{B3G9O9OF|6b8G7bx#dcx}`zmac<~oB&f4WtR4q*6dXpd%r|FZs&!vPgM*4Dyp zn+eAo-3h{cOWzl=snlcQ@0T)g`s3=90L|`NV1|!t)WAcSU-QM=UZdo+!%c)Kr$Kh{ z7qQv+pL>t0AjAyfepOYaj8E@&HQ?6#;(Py@1(IFfqVK^S1XcYrF41anCByo8NSP4( za__rpYJ#G>OWoK(ApSUtXbfv`T&zAzRQg0^wb4wBAkz{MeBk+l((m-y6X6WJYnczJ z252DiT}@l=t& zkRl{*+F^at7DwdQj)*isR7sHOHtl=mx019NAJxDxMtnKE5%jl;B-9NOWp^W$-Wm@R z|G3qN`B0F3N|T_o=<^}h)dM#aB_txaJSRqX!z;om9b~}Jz|XX@Jm*RMpWK7-I7)Qu zqHzH;0Ty%2v&Z){)o|Ls%zQ}nGM(mUeA%yp3XCt@rd_Qi>U^~lwlTRYi0&WFDOZ-D zRFj5OU5kEhgKOJ0>bKcArrpsqA!*Eh^~9EH(MH*h`eP1lI|M^5*Ue9JR>pt-M= z{W0|oun;iy#eBjUEuYE48mfZyo}9H}ns23fAidgX6is`?FkDd#kzA0mm9^Mgj-69t z7cy6(A7fa~Z)Te52;S)CAGBf4iqSWrVY&U>MhV%`y6JHQydH_M?P?VBG@W9 zRmk33etaPzt2LQl+4v<`*Cicw@j3CBBQ1g$wr776j!DU0>vznp+0X+qMvRH5@?y_C zp?jz*^UhnD_H(yM_mgUgUpXS(D(!pbv3$@V``49Rs8rf*MUDCGzrDex1A#%LkRAja zH1R+w^iNJt-GCt?9&i*x@y7)CjgXyuF^=dow${^XzWT4UiMkng@W_v@SyxYcc9c_Z zWjQtFdAtqDoAR(Nc^@_0DT*`L`{8_IuW=PnB&@g#TZW11?p{m7xUfAhTB_>* zDJlQqD*o{~{J-wwziM_&MjyjUX*WCeCl&FfG7Oc$hK?B(xoeI(8GbvwX(vA$z#x`m z;1;mEsTiplQvRr6&#lxbXnCJ6yX*b;5ASaaon3LT&LH={o!pLVZP4hRnDa;$p|IS` zT=|0F*RGjw0I#4=L>uuy*+$twD~*Q+VIGAby5tVTFZ3uxbu1&t0&e#*A3?BkpGC2i znP=PZmx&>t?97(_x+QzQERxzB5k214B6Fo9BJ*llqMK!ynw;Um8EpC@-SnLO~JJnA84 z6XwN2b>v(&c+eqt-fukq0YM7!ZSqzAL>@HPTk;ADh+DX`m6Dv#obU4>0i<1NVgtz@ zh;`lwprow#eTNus?TqGdiSe@M>Ef)2*FBdS{EYhoe-z~E{s}vVrcN5vpw!X8Pndmb zj4MgPZ1MUr4{wW=Of!mIH?_+3e7N8UAvmtJkG1@=_Xh#~CvXa@yDmo!HI=Q!0k~(m z%TQ?!a;aYZ@;3__z~$k9Bo3)N;Y|{`TI}rDD3527848usG#7K$d$M;nnv3 z2VaFzSof21sigrbyVwGl-x`E9M?XP+sw}U9P41-} zkm=zAAqYS?E+~R}l-s6-PGCLx6G{+rm7ttW7LI2?pOfz+ADw*s`LvwTydSPCCIZ*x zAN=uc6@G`e=ywu5rKza`3q z9u~)}bhTn5e0M=6GQ6!7J0>mK*Y`rEnEFjsP98qwdBE-ewB-K^WBw}=!ukpXM`mz? zx-OnQ<;IEqQsLxt7!Db@!ShQ=(}mI9oR0?(siUc`Qve76q;?)e%k^jkN~Cfvyki_Z z74~`{=)=n+ZE;GS$t0qH4RXr-wY& zRV*~eZp-dxYVj}oxKHF5PV($9q75!@x3K*i+~Rh^UF-yk;p#L92a0ThFd18p527t=GoRV;>czl0+ zn|pa9-p{4r1s*6gQ-wGTi{*-{PQ?l(A?VaFJ<#}Z`Ryn$F2ZB*k1zQ9&^rw^`o^na zKD`(H!m?1?JozpjIP}Iet__Z7 z+tItZNtC(7Z^TP6EDYL$Ni5eK6@PaKvH^b*XvL;GKcraAu_)jiy>90+yy|n!rT+nL z=B*D)KWg;$Y(Z%3Vh9lvFgLzC=yj{$Y-J6Z3RX(4%$!^XI=w(=!nss*9J-#E!fpHezqNKa(v|U@M@Yk^-y!$Fr%>W9X8k(3O;M} zcsTiMdMLAJ?^v)(m=KsbYRLQ)hc+KRZfG=y+~5#d=%v6cGPeU0rt^o0uoKeTbZ0C$ z7iz*1@W@e|y7fhRHZ5I~p^EKp!LSs=;|>l4I`Aoan5IC+V?@#e&v>@0;MI?_RD(+Y zPG5;qjk;hftq*7+F)UuKdaD}jT7nVxntMD>u*ASRU69nA?ucDuAzeq4(|e4f;2j>X z&P~YG{}X4BQeqba&Mt__qgvj|g_eHhI<(u?Ovd0RAunoQ)3=1Y0-(B!%XVmuw+HDp;6rG;Vo80pll$!y}JV;y2Ya#Hgym-t<>?w z(K`NIw&c9iU2SI+4#6~EEe#k6T;G4bfqO1F9rGL`hq!R#trSx0GDS*=8c4y}Egg2* z0jr^4Oty&pYNJy(t%CNK)z{~w=WbaYX#E&Fo7%$}QmBYdDk|Z5F8)Tx{eB>(44G<8<63p1LQwgBw*MPTOr~pGc6nSHuPVr{LfWl zoN&2Pri#kuV2+1Vue=L#s%<{_p(uex60zeB$rx=qn<7VQX{w-pd{g3#nX>pQuW|QT z>F9#>UAoZSrO6AzF+9Xaq|Kuk!pe&L+gPN9Q-8f)y%w2Z2BbosvY*`{ALiw0<7TzO^ zReYcx8#-Y#icda!uS1gBNap9)A*&WHDT>@yifpk^V>c z*kE$2(i0)zC&VppvM2~Si#U6w&t0$kDUG2ZTFBJbCx$ciLGX^I9_WlAGVh{};}tWZ zqdgJ2)x-F&5XgZILRs5Oc73!TYqLi=nq)t`03m>^yxonqA~!(W(da4dqNUh!)Y z^_#3cvJXF3-+h)Ha+wwa-CsBQ$uLoPoYV9-UCnG3Ly9SWKNt3FFbz4HUpu#fQ^Wp~ zI&;?n{HWz+6lg;s*ePOeMgBa55hiIQlhbdb?mG!(@7`!p40HA3#%kbjzSj_LCpUsuDO2NVo?7%e)<#6miCFa4 zKKkP=QQ4BwJ;rLRDrF$Ydt{Mc9^;a8rXdn-QjY9{N9%r32S{esbKDccVkUj*k*j6l zNc=bR^fx;7H|2_7nlXCI0`kp*Big`$XzF}cTw=O^lWC@;OQZrM-F@Vo#8tG>w}ey$mAMB9zc$6Qgm*|LgOfwQlHkgE3)Ohj7pdkL> z2av!{%aQ~sh8{g~q5g7^FACKEV2?u3XXR7sma|mifWP zjqXhSK)R5EC7=N`){HmlesF|9*~k*6?tH8c%<9^MIO=!?xcTroWs4xDXOVSQ zHu?Xf>@A?G?%Qoq1SF(k35Y1QKqRE4TS`h=Kw1Pu32ByecZqa&xuik5K|s2@yJ69b z^Yh(%pYJ>S-f{2QV=#sc6p8hJYR>u0r!CUurkPza=1Xnp=b6m_XZLA6aPB}~%1H<$ zF8hrXqZ|J?dXPOdjeP%1qlP_(gXQ!t0=Gyz1C3Z{uFDSUUaW473D-BO>(ORR`NviV zCz`RjU`=V5oqUsmL!osJ@1ynC05B>)O3AfB6kz_s&)dS72Q!hK8G8eKP){%2eMKWV zXevN}r2yJu&;(W{!Zn`KfxXZ^k+*5wcK7SIOn~yr=>#7PrC?MQ@!W~T2Ys?SF<>T_ z>IdpA;>TIargk$3$jBrD&!6DrVB_;EqA7L}n7o*MySy{d^e5+WNQHo&#p9zPh8fQX zlFK>tUY1iaUuSdeD1C8PuHGvov3j+t2idmCn;rs!k1?7K1 zVgKpe{=eN4{vA4KZRM&bRuk0@u6;d^~~FCjQc|sjc>I1#YwMaZV6_Den<* zlVBzr^KH-imSzHJaK~DGH^w$ne~Dp1Ntb4cbtL&mu1O9UcD?4P2NEZl5lm(j^%3sk zVLsq_ngdaBNXoAYiyp}C7<>avd&8SbLj_&F0iAxf+`MUW;7Yt>ks{?YPT`sbVRl8V zk2BdSfg1US5BCpdr-7W!PAWS6uZ7KaHPw|!K&2jWli!EL_zt4bPfLT8$|JqNs1d+J zH6xGK{jh2@-b_PQ- zXUfmPQgw>b2HLIL9DtswB+K;x-IuwY%e^d9&=JN2q-2)$$c07-_->97R?epxZyx6PBIxZ3phT5^^=A4co{ z34D%i^1?HdNI`spoP>G)Zo3M=WnuZh#DUOhO-2OKI1mLmZC*RvI&L5fzD7K3)hpma zY)7->vcZI3<-6xvG&%5T9ns{7pqDW z(5!WwUK+*SHa{SZ2P0P1rhn-^U^FG%?uuh@-Nc2kvx6?UDTi(YDnBggKRg{fMHxWl*=<)T+pKCi452%W7^-YFvol5gS2XCK_Jtifnz z4xcx^ExHRYx?8<#pH91Bj&_t6s3$z&efsh-Se0hEUwjX(cs)(Iz?-$XRhab?Q)^2TgY32<;Jr%Zkl2% zAWi~&tDsgRd|{z)6-bkYP&~{Ucq2UGuanxroEPngGgnc1{4i7j2|{P?4CphZow)2@ zl42vEe49VA!T5101#ki}E=JKae$b@W`aG&)NjhFhTORd5ob#PD-BFQW_Zdi>a{}b_ z=P9^g!|Snk_xkoX&X+eLeP`yB0Jo(DUQ|G$0rmpHW_4Bsj@0xdY4$=ywEkc6Bb}*=KfLN{a3a*qEkh!G(bbJ?KGqSt{mZ+-j&N|)tHQ!|59?Y1Pa$<&p+C(`l=2r4Z+|QWiJ4lLZWd;mDl=+)ATE2v)h*-`Ex7M!B(LOS$V+Ub=0OD7%jyz z0JBi0@Kr;CKmg7P$WMUdFZQ#f_*SfJE^p$y1gz=s19D+8uqApbA{z|y|AH6^i& zDdN22Xjm}`7;U}HQ30!{NVLR=j(#TFB76&PF3zBn$Sb*~unmjEr`v|MG`<%Z4swZx zSmvI&85R_e1$p#;Is3@-l3G;N5qna*ugZNx9o7k3v^0>E8cN^CDli=qaR?4;I@U55 zMe^0InHIY~Q7kxr7fIyy<-+q*;+ycc`M0@<7`^>l;(sYT3IBIHXZnfc-&cq@YJkM9Zg1^pI%}@Qbc(_sw0T*bbDvJR9WjFwG@w&9J0%eXTV%V!qFloc zDeqp$FvPe-AZ$y6>C{uNSWfPaJo*#vwy8LerVOCl+*7d2ompgDQ(ynWg~wnGBGKNJ zW?m8~Gk8Acs{?C2TwcL=!AuLj9FF3z;FU_RtMUvs;cs3ZR8x7iv;G)7k?Fdm05*+G z;D2#$a$_i%^E}r=m67x(i>0AK^Gs7ry)QUCwd_>-VC@{&=}twvmNsF_1sJp}Xu~!M zCX4v?^^_}i0BsL+HK%0(>o$o>{<~3J@k-wfoo>B^^F^@${{WbD>U=A(DH#kdIvG(e zmQH*IRA+Fh@-6B!+A5_g}2By5Ao6b-z}FYfUgKkf&U(5uih`UjG7IfABejBVWo@ z_q1=gr!LbCsK9RPif@Okm#yXIT=Ok)Q#7r^vmcXB-4Nih2<4yMYwHCLf$>#}0B9Mn zB5<)uru{e;Soe4F>-Ty<*`38NF91!KzhNi_tc(HWpq!b)*_ic^eyx|@qbwVQ1#qgV zIFEQy`rsjOECiC|xwF636~GRJZS0JY2jHTdJC?zA=9~5s2GH%br@RE4I>5he;p9M& zE(TCS5>9&F{icZ%`t*2cTZ{yYck%H5S(t)2F=EYZsVPJotON%YA`6ECrl~0|`@@j}Jgj;BUE-kJK zcp9<+)s?p~rp`epmSWZzUXA?;{(}1v?SwTvGTVZ!Skha+JwUHrRt<#F>Xn0RbPHgb zgGae7()e1&*^sn*5gwHC6Gw#_+;Ra_$$o$|9Dz&{IIHYpHemg$QTq?B=dXn~XDar; zOQgv^88uAfpq!OW#`ZMg^$fFu)rgGfz#0unDYP5UEY*u7r+fpKpzN8y2a&!Z?{;rp zlA%-D3pgGo5#0@loT9?>&yM}(kHVl(!f1MvuSA`mwT5W$i4eTWiI*2VFE3VhLO5Pl zu~iX~O}U5RVfbjHlSYf7T5#(~XHB_+Td{SB1}5h7zV6AD+bjXqsi`sHIj*s}%H)HM z5vs6XTwF@YC&?S<$s4bPHiq)7E@K&k0Y<|Yej@OMJ|>Z`=K`}SfW+g7%H{@!RQ_VN zAYq4O!ns@7NVpsG=or@$QJl2GULnJB#nR!Cs0+{jn4i#k`}|L-Jb4=lxugu%E(YQ^ zi!FKZJyJ?%+Jzj%b~#^CFS%sadnF;y;>Ww^amP-=xzX=i+1stAF2otbh2|UtPmc<9 zUwK6&?n(9|_O=f!Yu!~z@~Uw>Nwp4(I<8?&UI7NoOV!)mh2itOKjCL5{+F3a*_{zt z=LAIj;P{UYMeE?y3n3NQo{L1D6!J#5C-v)UYM2~iwT<#}oN9HI07(~qvvnY;>hMzJ z9Q%XErCI#-n1|HuwmfG2H3Q%VXhxFNic+Ct#c&YGUb<+Xk2qGB$;F=bcAoYlhk z2E8^752qi$fFJaE#rGeE@IS%f^(!@PCMR19S%__|p5(8AF?VSmeM1LGmD3xP9gmx& zZ;e-vjE_Q(Z%?WnebQC#YfJZ@dVTdUhH8%u;-Gc=%ME^9jN`?x*F*0Yh&rHtO!|?@ z$^0|B-R`~OsOL923BYMG(=A^4{G;hdvPNIs=g}fZ)U|fj4Gj)zxnft7E~EBOn=~^T zIOSLQTRHZ~?jHG1R)uZ2yuutZ@T1vZ=bRs(b}XG=!VYcB(Ct)AC@7DYG^x?uQD+lj z-o4b{k}Fa=TejoV-FZur*PY^WW4J1SYk7?l!3Z@UN92f5N^fiFr#l{LLp7c`ZL18c znMFa)8Y`p}*SaY^P*}B^r*txG*Q97Skb8nNmUcB@?K%NOC* zp>jr9>MJ+~u-JjGM=l@8Ca@%;7)fXORmy{$E;)}nF?Oq=ij*Y1oF!^`lNa4G=0azX zU%5uzoSLP9EK0-ky!p1iL;>%Lc3Tmb0;pbtlHe^PK!U*U=>y+?-h?5pjHhp?39-;o zy~O_Qk87$Xefpm}jJbZPRIjG9q{<+3V*RT$jhflkR85hj0<0h74BGW{UvaRMnLX{I z6m;)Bc%|aI!gtZ=F*DI4diYWa*{p1{3u4B9;k-mPxNq9bJ!}gg&pTx2|wtdNN6R0`s`;?#RO^K*CW-MMZ&%%X}@X90TOP@?1)r4yWRTD zZz+-4do`JRg#HbGkAUAN9rQC!D~r8GQkU?r zWbiV%RX#>d3RYddw%E#QAl;D4UD3P!j^tlvl__dk5!PwjN2(l^ut zs~6#Z+bR{^K{k>dq#2To8z(C7;P+>XoLZ4 z6ov3>#A(({hXJ}b?+V#6`M`i83rDDKp+adVg~G@!k4`Pj+WG$@FLNxwFTejXHN7MzTN-fjHKHLcf?% zJ#*Wg-RlVc5Zt%==+sMvcA!Q7SFrB8hv61!gAHWFRL#j!yRgY#t)s^pr|<6BnNzOn z#;wRb;TPZTmP4&mvO{L_#V@CJ%LO(Fg*AMQQZcic z46Tu1x77X8MF&TV9Ybadb~?wHaIL#4B<$cnI{L_4GilBFb(Csrx&z3by@Z&dCR z5rFZ|zd$ioR#dq;46qQngeLyTdW?~qX~^=zoAIzr)c-g!u)tO!uTXyW8rw^3GXuQ+ z4VHh88fB9I9w(?R$ad>**t-H{Q4+m)o)x@K#!y8`#f?afltH_|^CKJ!_Y#Gb?GSXw zCk@u|r>k<1vvD>$i^R^03%<6tHYa;l?U6^N0_Y@sdMeWR;5_vkTY zB=3!@HUvqGC4l@Xy*bHPz^&tcaMd;=zVrCi!DEJFwAm63Z)pwOpNobhev`~x05T&9 zxK|q!5y|hWblQvWYvgI6t)QeBt(X^iUJ3`&URz(Sd1`x|?hg-GMSt!{ok6w5nQ=4M z0#MAYS**M4&MmiH@byhemI+JPYj*A{pZn&LVt|N=f;=>{dt_#}HaPQ3cPg9X`hiNF z7YDmPk1cA)&wY7aRkb|+%iFui7}3LsO^;JO@YE-zUF+qFBGe#Fr*gE_tmA?WE7g@s zYin$TmrtkctUD+~83d#bb5$UIQBg#lU0v1&BkEzJs}|qXNvmsK!%XDtSD#q?lwbKB z!u^5G7(XnA|8me#h`1BC>74GZN!RnHQ*PY>WX7S-IrF~br$}Q6v!8KJTrB3h5gG{R!Mvq9j~);@vZN@F)^pKvnQ5Qv*}Hm>>YXKRc$>@#mzLz z=79$cEA%&?d8~7UHqP{g^>TJ@LZt85qoE`Ey4el2ER-YerFw0KU%o^mk?!gm!p;;= zFDf)Q4wE!S--&iMUwrQ0I9;`XYPV<`w9n~~_v1{7WZJt!!N}O_9jX$#uAWp^-)@I| z<)%QGD1J()N%AriVw*B!#|ZBU4VMFkMTA8F4`)y!RWn@69L_p7)|Tw8>4RA3w5814 zxKdHDUF>xuzuN-Nf}0vvGFI*z|7mg37%sIz%n=-H_>nlV1Lohub!`&_S{1Lu7xKD)3qStloR#C|V<)A`D1$Hp@ zy6T1(h*__L%`dA6ckrR!oTnQjiLXeu>4bIb`5S^6Vk_CaVVTNW?Wx!UX?^@ zJQ@2lVs{9~4zh%~b!4YzoIj`nFQVRVIufzKN*mrySn$OyH4VofaG zG9$4M3t!DiwRRrAQ&4)Po)C@0F3ZO%W&1vSa0_GZ6Nj5a;>RpG@*uOPjv?JAhdU2x z^ZY)Un@@?Tb5&lO#2<8#lizEe)9EN7J(v;h@`})!qYbC4xIrn5<+oX3>fv1PhJLK_ z)M8$;VtMMSOR)WLx5J{f8GM#_Q`lLbUKmXEk^jO;N%F1kUG&nq`{R#HlDETJ33st+ zrdum_Y~pqFlDrEJT-?<|}$( zmC2+)A-FWbM2?pAmQD?Geg3_MB!_Buu+nDTs|+@buWZ+$jM?r-mXq=$-HFn!%Megs z4`5O9c81A)quSsH(t2SGu5KRB!De`E6<`je@G>vsZP1U;1TgHCHVB(IquRX(DIa9K z#f1*E>zfY`n=~cHar=e}&=QK==z!7H^fUz*7gr`1I%-RX6a+>1m29+q304>4?z<&x zBVwCd+2af~r0DUhjQlyFry@2ARWxG9ip zYV-(08bZTMLH#syhIi$8S9-Ab3sg{A{<9VPCv5&RazNerw>IoQnlgOiBSeUQ#vFAx zEri)8v1f0}XA;^krU<&wuxb@WYz+ozyig^a!DOpihe zF2k`1!U6W89-()m6O=wDp{ZCg+pOoZ^iFY&9YdN1!_1B7PJ|Q%FXg2bs50bP*62Jb zqRwc{a^NZQf+*SVGoid|Y#JC%yQ8Vt zMH$mdGd<$HLz8d1#c@8jP2DZ1+#F{DyHd*&zc_w1t(YTkthM;3s9iUAx*ne8) zo8O1gIplvHqDW{bC+`5cx!(YKJnJ@sKy(s^C1?ejbf>!Ej86^;UNsg!dJh(_6Mqls z8)PvhfOG|fuC}#}*vbfJ?&TCsePK`fwEi?E9-n2pYoT=c5#N4gTS1F`( zR_ex8gS=O-9sb>1!GQYsNm<@g8XkwM#cY1=Cpq9>Le1X|JGaZrWum#e4LFD}V`V3uxu5AB<&_VDLxt9ko6w?%N z>QoW%#G1gZIvM?gzEg<}<4WWy4i+Bt>JvOkT3>#6$3t^MjG|?wE@2aoU#`U2iY?Jt7*oS#$js2Z;mjiDyY{)_~C>i@gTE;2jBlWMYWR zlk&`5-2&bRI%1ANZ?q7#cR;v)KhOlcG%XYf#3^66Jje`i5X+VW!hv0yj%>dWdi6kU zRp(cn1h50W+VJ9}c)A$bUtYR8UGUkaR)6t2KV6+?_-LVCDx;s47V(N%Vnkd??KZK* z>%tmdMi{VJi&8oArC{w<-cJsrhx9{XR~!{Li>Vg+uE*Ser(sxtw54DjkwJ`RnNKzDh>YB|UxO<34e=YdgALiz*q^nhB~e#8 zx1kbfoKqe0X|9XbQK!m77rsK?q|fk07qfgNE3mr~ds>lNLM}%|bxZPd$a*&fWRxJZ zG=P`57gdR_M~-B=oYBwr(^n{@-k@1avf(ZaS$8KYA=-U5!3_z=B*c}FdxN+0p@&BY z872|@7x*p7L_>;8O{yKlC_Opsefvr=1HZ;yt-*sN@%M9+FP@h8O_;;`>53?7PpsQ0 z1RZULDHFW_%%aMZSp{&MC-`Z^egM#T0rl3 z#{|N))ytt-WOurA> z?Y9bWfS#cX9vkU^W_iQ+njvCwu@eH)yNwJ-I_Stc9G8MEJ)qcK1kRrw6GSg&wJwiw z;_^o+GP^?-&q4$9RcYc=85}7ivm5T-$<@0xCc7=8$DTK(EpDpV15a>8u-#I|(x?7F zI4$67>f2<-dXK)SlvGP%0zvHmW6}r1{(p33e_b!)6Q*q)qph+#M2t!cQ;Rhi*^Z-htHrM2kVF2aRD?5L}jlu4i=<2EaGisH( zQ_6l&9(=^?=Np2frdd(zq$&LwH9yp`-?*{V6t7_n9-|RTJ6CdM%<;wRkjeP&ks1|+ zLuAaiC_f4~fr10%25!5Q(Z!3OUaZ89pG(nPBesP=NhEf`FX#c9S7FcMEhh$!;9!79 z{T+g0ZT>=12150IH|H?~c&NYEIIBLBJo#BejW1b03?5%JIZfFxDw&<82DIhVMjDXB zq$M(W?kKD*6hYl-Www3;JJa_5@UX!nwC@P>O|g&K8=Z0c3d{Rqk`pw1>9*p$RxT-F zqL*oXciRKDzy$7T+}&IR$N7T$_e#+lp2Tvp^WAy5%}I6Ofr>cBEz5`zJtrNGF+(U^ zgO>Udb3XiIw#6S%8eclGp^4V(V4KSFFt(F20f19Wqh0{d<)%<)dibBUsgRsf6Iz91C;I?zW-X`J?&}qf!OHTf zP)QZtQwZTKbbS8BH{ypOzHu+yZio2grhCH}zC&*$yh;e%u+De2zo|cvoG4`}I_cuZ z5W6ew?#;^wNa7-oiyh}PRt{10fZiw4MEa&7gBG+q>A5)F{y`N3IG%-5 z?!`k{veBXCwG!sM9fmmgP$k>g&eQu66XI0lbWZC-XxhFu)mUwW{ezDvDcU(hEir{~ z9CNJoFyX)Mm-!Bfh8mmh|8{_mHB%%=^dpF-6_ZPNYN-5g=CH)Qx{_AJ zHNKq0OBU5EnW3`#^&g|gZ|E~6bzYS;GzK;Z1Y~yua2$k2Bx3R2WN_?6OScp zHRsh7zMWo{yZx@Wx9uJ@_Mh-q&ds=Fz90? zhX|a8=!8YZKJJo7=PrNeHHWhiy8KDCu5RFzG`TW`FiRr6sFNTlx*?+4AW{R3Cq+t?n|6Ta%PyL5s=Gr-tmp;29s&3G z2H>IxVN+V>efoxLBTcPq1{av`t~`*+!3Ic(cv0iV`Zp~$755|M!yVJ&(v|m0BB8|= zFs47U&S%kvMyWPVRUB<_z>lo=T+CO11H^Lze@86Oh(Gw!1TCS zg+1NxrVVK=B0YM&!}#HW-7a}q)UT2QDHY$HU(Tu3MSG8&uX*im*ls?D0)a2P;hK|Z z=kzmV5n~Mv-#aAxgQIPF)W5x(`P7Z0SD>3diE{6mQMdvz$%<9U5^s_5Pf*AZ+bm#P zowk6YAZr7lnVD)<0DyUAl!ua^xdnQ_d`;p-nwDdXfJqG!p(5J}sl14r}YYvBtaQlDnUzvDaF+mnYU~%saye7O{grLlq zUnuDN@!&~8J43I+6n-!=imHkrI;6?q{sa_Tk`NGk?-5;naxWrbJj+GliC6aqVN#n6_r*-!w@Ea}`z=|MjlIq?Jt36xb@cf;2W_Ofzk0x_ z0wLmKrCpGUHhtel+=;b`W)2=P5;pgY*0DG z%fmsMF@R(F)Z$d|e*dZU;SEr*_FxVjqhW3%-z!R1mUS1tUKR8WSN!Tp;@iRI5gi+G zCvzi>*WeL#NU zWO=p^L1FzdtgkDks@@kRSMf=l@AOBq-@!FF$RHp|O-QNJuGCDk_KTLS%$KTzrTFtv ztr^>4$A*EaNs$DhZ)O%c@1!E`t1t|e(i*mD${x-??dUnym!#z6z@tT>t){Ui1YA6% zDEmRDtUzcLoD~^|W8o91gc>jtRU~yMdVSxL)O0|=?!RGOh~RO=l~Xxl zO1h|wCbw+y$_A;`@{*}6fx!vEnxEjk`AwHvj!=pwe1{NY$;-XvPM@R#{9EEuXx2mj zHzlWf4}wik0q5wY0(~@ljG<(Embzd)X|<#!-`*JU{SUyM5I3&N{f4+tTF3#1^Ol)v1mmyIHL&+}pn|@W}unO(~q+FlI z=2P*K9OpACX^w@9x4F-hjPaD0c$vX~LIV421cAA|=;8=p*}c;5)~Eh7YODDHQo(sf2{?XgM&|k5@WKLt0qUoh`ml>wRSRO1k8W=Q$k>961EAzlPmO3?5AU9GMZud znS_ami~;1?%QPfk|5R^$mJC0#!6R+OpWmJ34nH*#i$|x;}rQHj%;a z0obr+^2BD!gxQ&ZWCWfOXh}I0l7}e}SG2Z}y=|Tw*Zc7LaA+@Rk!CQTJZPL3%|yuu zOzP@iCN&-~sZgj~Cl2k4{ud`*2ChLHFW%*_BY(}$<^Q1 zge**SjR%Ol;u8t~K+em$pULmoxdd%oe8Kg^u6)M?c?;hc5MS{^Kq3D+yoMW*$UY< zyz>{m*{aW3EYA(bRfe@eHWK8!ifU3?U)BB?$M*9Wb{F+KB#rFkl?`7YEr8kvtv->V z^poPhy2m9|{SzD-J-+q*5mqjsJXzJ@jDrsmuamReC)UpiDj8zIe61WC+A4_Jq#-spKd3W zktsBTue?0&$)oMh!N8`U(gvq$Y@N2H9GQRH3XcU}I-8*yM`+gpTAUe4yu*E0XJZfUSXGHf!tSnMCsY%6g(Y&So_;BBpaF-=6ra4IJ@w`ra^RU2TIq0b1Wu&*!k3m`cSevGq+C2$x?2w<63$g}m&4|l;jc3R2XuBBjZ_xNtbKvg&zk3JL*UE64PTE2}7VG4wgyjL0 zBdP3$^LM1?J0kN)o}H>5)JZnmsuuly+~r}R47umPtCe4W_zc|<&2pD-Y9u0)90pI% z`k2#`=J8m^2n%K!zCN1+TU7=`(+fg@mkC*BrJdn>7P{(c+Tf?JnrMinMGR}S>WOTQ zmV8>~Eo9WhuyZEX9`jW@_^lnED<{B;j|F4`0nRD(zr+H8E?PEPq0P}{X_zJLb{MDr zWnJK$qf```c);7}K;ejdO**Se#Ld)Hl+hp%qo|FVwzcHHrZ!sr^78o5Wy_V0Y_|DQ?$(~s}LQ4#%ev&;ZqI!NwclS~z5de@^M ze$7^d`{k(VV5mym~RPLxuBW3 zAsc7my86$;B}NsDlu2nO75g&ivY#oTa_+A)DcSn*3B0rYGFZIy=><{M=hH?b&Sy{S zv(EZ%+c&9}y3>#%{;5}_@3}fUH{1h;?K~7#VVI)hV0LG7PaU77hv+@CTQ&k1zgYCc zrJDP7kM-(E#xAba&UG9;JIYnE4?mHNK6=Nprokt`Tsj}(eF zqAqqHfW4rFdPC#MI2!(?TKETq_%9p+RI2~3Tku8`qm*_&d!VwIwSF~t;s$H%k1otG zeIQ#VF<4AI9p*N+0j8F{etJk-Ya*Z5_r0b);Q(qZ#@N^DMPqg2B2x++NUx^m$?H2I zTXI!*r1D$jg-1PtxL~rMn9|ULT;^hoGh;@YQ;pHO>}RvSME|MLX@msC7~a36!Q0^p zDpG$Dn-SYU`ok+ZD%hgf!@~w$#zOCnUl87qiYIZhLV1;fuZVzl;xGP1L9ZvKdZ2Ig zN-nz8|C!3L3&0Z`Z7)+7zHC+i-5uZu4;~8~vc>i$dhv66eeWll#!DV^X>~k#lTcgU z=viL*8seS0Lk9-fvckP2L|!LYCfYy}fWmWVNzcS~!?8Cug(hm1aq#!iuizyGEu0c^ zc11Rr>88ps&XhePUo3f(}1V{r@pvxdUHr&irOVzI-Eb%5M`&K_GnbWYx3Nt=y5w{DT+B{ zk=L@_D*!>+bPDNNb&WpXpi*q?K+MzT zq7#MuqW=(cGdU+QQ`@^~b#?34zlMFj$I2@PxHU}2J*Wl6$0{m04Qw4AZ_QgnJX7+) zWVeT~BPQx7kt6mgJLP7@<8+zEv+IN#M3eY7I4Jfp$Zz4o3DR`YbM443zREwEXV40U znqCCQVf!`vl|LevwSZ|WNDau7Xr2@ARceDDWp>QTN3vSca_fP6k-xDi0Q26IUkY2t zeasbeJ!S!EfNfw=v)a-6R)uZJs)V@qsg65}oinA}5aCy0GnJw-M$(Y~jWRrhF3ljQ zv>5`8zmLEE2g~ztL-f8&)!T)*5c%ojUrvK^wC&Jp92MW7r%b1iXCZQk^2diDbNdRf zL(g7MW~2g6<`e}55Zv$gi%~Mvbj01)USiQU^q0~e48aZm2I2jKod17;=Xqd|1;K+U z@=+ildj9%;`Fkml!=g+RnyrX_?SY8;v(Bk+`%sFPBOpBeZFQ3jxQnW$rWP6zu`u>B zF)Jq2eUXj*5Mj+=KV5v+W3B4CAAxm#?B#~qk^~Jm@zzY?3m@dXUvb*7aL7dsITi2bO@rG~=LME_h3l6M}W zXKV~6Hv}%^Kh5cfjE>%{Y(9_;5TE&~iWq4eBekI~BgN8np*A5?rO}rqzo| zpt?c{phc*4a-ffTuOv#FTxB?+q7h3c6VA@VbLQV@jT;`7$cL@s*-#s3K#EB=iwiS- z3NQ1U=aq0>KHVYhRO7n;#VoCvB9+#B3>X{SGjr3nU!4n&(NUxwkb0>wdOGhc{SJgx zf{^Xvl1A{WRHwx&;Rk3puCd+c)gi}8&y7Moq0AtS51vTAO7$tP@-&!-bwp%Rr@y@A zMEs_dH4LMq=dpbtr#XLW{a8}w%?TQM7!wf9(JHV0I_LauYJ0pYhk=QyGUlW9mBap1 z{ci@N89*Zp1$4eC5oAFrG$;32A#alj3@V-2uzeZlJG48TI8pLxSm&3-=5)M?43J%* zYYWEL;%kqolt7|sNv0JgHVmKG5c`RgtXTlsPlrJsz=^?D^PB-3i2jA1BXIM(;;X2> zsZWQ&9e-8ob)TDshso8$k8!DV;a`h~o^$3sZCLScIUh}B3F#|6+4Q4HK9i#0Vw3!O zek=vjB>+;yi^Atc19@ES4JhAaeJIOjQ1${LrQZSH*B2rk4Mwlze3fqcDn3HkAB3R7^S=;?4KL$}~n<j9CctGnSqwRZHwZwmNwD%jI_5?%AWw@)zd z{psWsFZcg`&_*eI^-GH4*O6NqxSt)|v8;Ena&uYDdGy)izTGaPer@;mGxvmPW&`3F zX&b{JAG z-$76s@YFSOK38k&=ww>Vyo&l8R+BGKbi5hCz&<#9Sw~4;u6Jr;Lm5O4ukbPe+Mt6u zE+_W}P*!Oz82-x19I+mFu49(^GhpcjblzB^mvk<1e31j>zmJyA!V4(7qkWxor~8T5 z7Nw8%9rgMqv?S-zHhBFJ$v$=aPSaq<&uI_}D9#5Ene>P4Vw-92xrr8PLp!^e%F0UK zQ#aNLnUBkm*8<9K7GC@TO5LH-37O_sKNMl67)|<;2UIkF86x|gR_ADz7=bU|r=ySF zYh-cUa+Y-TW(pou-Bs@RT0NHHt+vC3EfP6*yv|s=q7DZ#D2cnphhm{^p6M#|_(JN; z%nv*rucs7JN25r(f62j2?p4>6ol`uL;{MU70CRiFI-$INftFve`=eemlOWWp>!`6h zC9C>zDQP9QR>l8tPgrj3jjA?Oisln9_6(xsR||W)e!cfXzG0{W zD0G)srO^q-t8P?Fn`zfH@9CsgwwYP(5NxV0mm%l%mthGw;2RB1{2eWLO&Z!#+Tex~ z0*&H7q6R!Pm~w#)d*HMaJii$HcWnKH*H1f}`9LcRqg`}=GHM@wI%=T~bVhTT4W-Ri z4Uy*XKPwaRjNiS0faN>Yq(J~;)*+4%TyTA>txc3d1N5q_#+Z6GtX4Zr$Fy>w|08Va zTNX&WJq{5%xnVB;{5>!;o{yA(h;qEc7Pq~h!M5^O+~e1guZ_}#Lty)qiMb9B>cJ&P zU^<-WUs#y3{K8v#R)w2Dg}m1dIK@kx>7@6#qgh z{yXJMxa$GB*9k_V`$Rysmbf!>9j2*Xp>Xeg!cT4b`VcmPJtkWPLtdM4GOU!Bor`=0 zbX~PEKq;fWPbuV79p&KT^{g@Ih`@u&b%8pTtf~3R%mdBLL`8wJ#R~wWpp6OqtBnKj zQuAz*agHpNpikoS#n|e<kZox7sl1y*M>xh-Vr`?!t#V;cgudIKODd)@uZ zi^Caxik;ww&$9L&cv_+$j{vx*H6tMOgAU6km>HmjIzI?3cP|=QpwtCSmzZf#yJc}u z65RjhQF!Y;;h*!?>Wrdy&z#3-$1iLF<0(F_i0-YIrW@^>Yhj*<=xl`Nzg_9#!05!9 zVWqH(J1o@AG^x9_As^OBZJBz9+6)B!{G1ND0loPNlzy0LuX+iF-#Lc?MPsJqf#avi zVj_P0V5_|ZN+09wp<^G}LM5Onsvx_0=W5G3!~7Uiyel96$0wKvdP|Z z0JI_&6AR^Tk0%b9q`*E%cj{N?3HKRt%D-)`?BXYuC5`rb{4n7kgJ*lme)gWhahH|E zRK~ISEZ_jK5Mo-Wvzc)!1{1aiEuzq= z@?^2R2%Gj|4yC+&ifDa!BmKnk23im_0?0?8VLl>oW6Pqtuo`_wrE72nVQ#uh0|4iN z#;Ee7l}gjG(B2t+=o0qT!j)pa=7)iEm-SIPpx&pqr_`|{vkmTbVx3t2K2aK%8>NwQ zI%H>F>vhX<&JcuyL6fZzx%NH2a%W=Z7Z;rx&yc>qi8ux`xz*!++_E z2JcT`XW5rD<3xu-d-&YDEz6m|BIMbQW69W5ShS?P;v`>l?w5Whnb?6Yu6_(04gQbzZ#_;J7`5TeZ3-e#`nNhzKBoP@|AcXKc6&6&)wBc zJwP^f`8D;^OPKO>@rPrDuNSZ_ST8Twx=Av)K;Q8=p2@UHUlb!2V7+nm13lXbnt3e} z&Ca?k*Cb3SgUmnhT^xAj^eY)L^nTt+J{rhCPEXiWk8=b>L<&11tAeSpse@^`_41nF zRFV^s^hbkjR)iHFoyQcH*(E^53mu&c4^=7V1}}Yd=8{GTNWz)yHN1B0xL_!1b;RjV zFv1PbG7m^cF>g#89V!QsZt;@P@>1EaVmLC0A5^!}_p9rbcKJ8m+5lH|eWDM2)W9yb zzq>+y>jOkIAkQYC)%~#z=~Xvy_h+=}N%8nwYL3v_WeSFEQk214KMZ@D5 z%7<(ILcfzaX!%pa^h~_VeJ4vi))*Qdcc7-KE7{O8)yO*-axw~g+6MmyP#0=*b*a4h z66YBwEFA~%)07U+tW;n=<<{(jxEf(;R|ihB-bk;ZAR1)Mc>_(}s6K*>5Mv}<-0O$B z-3Wo_TUVz|Kjj(zxzY_u7l)EO5p`y`{F6ud@VVVf}(ch6d0J>x1okmYv;DH6S&? z6*)74N|}OHDwDNyB#C>&7v*XFrejoa_64Xrfz*{z=ooVRSjc=y-#A<$8dR(@)1enH z)Y9A&20t&vihLO-1H#tKc+y&cp!6O@pr%JdO>mVB!=L!^ftfTGv3-+t5Y5;=^%jT* z2fy3`%-&CJfyOMV=RH_;{AaFOI`hlKK^OFWrYEHjDa1?KFi2S%Q5NkgXVc46FCdZ1 z-0jFHe;`MTvFw;sQ^`x!7v?p{T{@7`=5i>`EmixYM*fS=Tz_yK)B~a|?Y1Epv~aDz zj6^Cek+-CtsE^Y7IgHI3rAeu~5dB|LQQmcO5UGlp&p@5hVI1XHr#N|{3YO8FQ)TMr zI&G8xq=63+29jN%dq3IuzOk(NGSCf3{Xkn68QXAo90~0KSSENXfaa|9T*{*>Bcegb zXCa^VIkD>k;rd}a!Yimc=-|2-4ll2)bQqZajIYRv%s8O;Kw|I4-mhvreLl_11>0V; z@iOGan(5z*<88C4qy8e`l)kUri)VB?&T&^hGfSKkwr>i@PoW?`NHM-0-9U76)&gUY|z2ttPj@MOnTR4`54KTzI|_E zvZ8o7d3t0AHbTtY?p0SX2vp6GVT$a5MWT;HtP_BdJJq>&Gcmv_S17%`$v+&E7sdSu zw#8W~Kkzi1cKqBu`|#sKi7shXF(uQe(*_l&-b*zAsK3{HX8&VN9RF=g&7c+W)zj!7 zG`jrIenJKihI(BTg8m%r5|sCWqSX0pcs@w?UD9|f{cH&jWRBKumvVe^bid;$L8#zp zCI6SyDnAgwz_yY1CstgZGBYy+o9@R5-}5uKvEZ6DJZM`hMT!LQlDpB}Dkujk?~4)v zfcm1=(co?xAQJVN!%e0={0t3S=!#vM7#1;frTaCWQO z@HEV`;#}TQPRw;17eumq*6Xt|ww0N>G%lQJK%3b4IzH+6M^eTUv%rfecsnDN{;;=o z>Rl)6kNQgyi}9o1J3z#xV})Y58gH{JxXJ>aaZ5|u0e~3dvlVWlw&2}MhJKzXk3^B9 z4W=KL=V`oXwahQ{&akY%9XeU%w17yBMhbJ|tnvYw672+i*7&Kj&KgeyLQkB8y zhXrUCfBmI`3kx$Df8#ytZMO}D%5|58W-{hyWz{So_u94K#G<#{s+87bBE-94OO1%U zLi1119{1RUWX?9-@=Nsc%)=xm(vrCoxguSC@eH4$FPRY%XG%8X z9B-j~`3jVsEbDl{MgkFT=HfgA^*`f) zWyHyyF81ak2-x~-_Z$)p=BR1H`Cp8^XE>Z;*EX6$8X`duB}66&qBBYmQAdp^(M9h> zoiLb)i0EN-8G;~s^g1NE=!C%-6TSD|_vLxNZ-4LpvG;zDM63FJElcE{Z&W& zr|NYk?ki43+J%g|REONr>EGyvQ#$zAYl7p}6?8m6HTtI>zK4u{_;(_kQ*t{z%941f z?W_=>I599Z(b6isXvFKb;tYQ;&`(gVZZBJc_fG6{G7EbEvMP4iqO^OT`mVQu zB0ESbfk{^|`Ds#V) zwz4e3U_!Q-U$KORbb;(njWB>VZ7A9QNaR|~07lXGx&aLpF~CCUPyqzWf*|?J@$pv9 z!aIWYKdk65NUB4!W^-S13~KLsJw3wlHo`Zeg>XdNwVAQgFzX9NW*{h$74QWo&o9oThaMuVIUd`Tgx+y$hW&dQN}U- zDscE$*Ky^W3)PekbaPqgi}X7EuLXLl2uvlxGSNXe)HdnAJJTYbqI<9}7GEqHX@^7Z zrFfmOAa?@itKWI}XW?0?*+L%B0oDL_?p-3qlu9U$y|e7WyG!#YUhaDGgM#ix4TV*p z)(8$Q1crS|8-1=8Qum`I?5IzsdEF1%|5=f0O_YiFKru!;yd-__$qI`{y!&19XaCbA z%Wo%2xx35D%RW<-sc)Q|A_S~^HvR>Wo8g3054)_Z-fgn{M5`BKmkn#&g8`K%%NEVx z=&Fc%&OBloaVY6mKvW;#ko9u#(6`?Srqj<)ti`F!5O`3)5jDROaGTtgrx#Qc7kmR~ zWhk8wve$M~a`Nd(G0O(*&vqanBbsb-VgeX`6bfkxiXW~{ksE<5Tk(3vcUPQT)NNh9 zXD}U5IZDgg2Eo{v{kGXZ;$yl74WOr*R~5_RZTe*gP<}M2vg(^YPc8EWzGJY5uaxLL z`k4%v%M;KK-|@+2GPpq6wwtThKs{qTgSI;_ZX@q8h|fF8zv%}7s8w`NREk(Y{{6DJ zqA6cVjKC=<_r*w)AB_X-pl0k_RXjywd)wa@(@VCJT~w?^=`=Spyzo zGZgH5{?FZy3UL2rQ$q6>Z4#fAJRAG&(E%+{EHJoWLE2{*s zuGkkzjlEEFD{?G^d#&5o08-zs$d{}^<1vWULDm2J)p}1L{3sL)vanOX9y#EyTR%e! z1KamO=c*7kazd(+-ix3->@GjCUBGa-vH!4x1E4YWj#8O2Md6!kANdPqrnf@N=8PZR zx&ktqtmpqw$GPhld`Gk&k=_uXW`l&~!`lHyJsw@=JciQI_rT5d+w9Rkc3g9Jm8EIa zuTJSEm|BsLe`I#X3^9yQraA=O4^AesR`IqRCJnXR^22*-rN>$lN$>%Qw5{WiSf;-NskKtnc1D}Bgr6CB5_ z-{gK@q;|8e*RIxAr z?n;0eahmyb9Kacqfl6h5REIcIDSJBJXl?%75{$yZT~7$*Ec|B3AI=Qrf6TvX+winT4UvOH-5t5Ews2 zz6oc%3Tp*PLJU8f7|rJlfWrf{X5y&?ki&!nM5;&CXrnJE5 zrpz-YyfBgmHvoOM2=lT=W`N#+c~Jr=ej{Bn05V)ak5w9EXAq6=CTt=y^uM2tk$hB3 zUdd5tS3!#&K%aK9=a7~}vEF+0qSE)R&*wpqrIcm32FNK3)&3w%)-Oyg-bb>Tub-=# znF%*+9Os`-7EQ)NJqhX~9u@URwgB@P_WQ2ue9Chk(v`e=EI%=TlL3~)WIPl|wYXqO zoGP)@Z!2_O3J~*aTEFZ%y|>TKn!!F@FP`q}u9}R`Y+q+Vqky7%$q4;57&g zC*DPF)E6Qb75}TyK>VDzsI+wjvgsD_SeDP8!98GM7ZQn zuPPYmXRA-Et9*NM3+Q>;(p|)}V;;oD-whnB*yN10wDD(X^R|Duda`q)brv1%&F6UI zP1WZHIyUWNyCo%)lCS7Tp&>0$(?+-+{S=Ivb1hXTt#m$o4JsdCTk8zh% zf&BJo-Z2EZFqef4%PpJ4@!z#DpuXbeU8`tDHJRT%>A*!1dR3SBm84+EgcY8RmR2hAd{e`deb-c_CFDsud$X8@51h^!fwB~=FYT0B097v8Zh zFW}zYF%L7We4LOLXDDPHO+ixP^k#>QC6CV7G4z|Zl*mJ`f0Px;&Gn(*bAK#ihV~JG zUBSS|s!U?@fI32RJ%WIv63i3KGHJ|nG~FRXNgY#{ovhJ3(;O5Xpv>0L)cYV$R#|n0 z1zN!tWqDt9@FmskuN8u~!7`5cs^$F*B+(Rm*D=qOSI4eC=L(C01iP_i zD;iiSydl0W_F)W_E!|q8vK*zb5y8|}75BVG+cX~cbPLcmf15{6`p!HeqNo2s!wo5Y z@fL}pc&u$LBXHoYO|w`Nb+=v-)Xo1_>3lNuzok~e2meoK%80L^>U3A4z*kYXYnMRd z2m^!Z%y{F*3dc`DLB(7oxC+px>!7~3lc%98Q#t;J7ROf+mk(`B$gjo4d@(66ATA8+ z2bVAq7z>t7M6lUk;bqY!KD&DIQKi-73eFs^l0?9HZv?#l(tUTtBSO=tE-=22@~(k$ z(@x_CnoybkrNd$^ITh?_i-R0;O+ap1na%raf=F3Oto%m%gfETgIH}!Z(=NGL`h8pv z%X<8WcKCY;Y#~q@a4Ohq{A)o7_Kp}Z{01brMyM4Yy3kT6Je0lbLiG^F$4(cW&ceBr z;v@O|XWLxVri4( z;{xof?+C3jBh`7pOnW&9G93P(6XJpx`y4*JABeQfRA}Urg2jLP&X_A6kPLU&=l;=7 z%<-?5i=N1X)U5kk$2!0vaGfZ*{^9gtVhyMR|U8xt{kH~1AE;e)IMu4h0*iBE11}6+Zib(D(6Ey%m z1pq`@e?uDHkn^Hz(R^M}^=o>$Pwdew4XqzR0SMSMeumrQ>D!1r1NzFNs4Q!L3>zoq z)dXwM%13LRcnANI6d`_|!OZ+t|6_enTu*wI?Bp^U#Qq=(zw7m2b(eU2Kn!RrDDLy5 zz=f%8)fz}$K8t#i+OLe@^~5vzL7h8o_BzlDZ`DILIqUSho;LFCjU_3^fo_F1NuFKjQyAT%<44*y(Rt^~9gZW_{?AKU;#*#GKB zAcMd_8V<0tnlJm~nO)JV=MB9#mn`cFgn;K3b7klm z5m=1r_cJS=gn5{5T%alK|3Sx$$GvIgGvV1{@n`yEm}GR#OiT55pJ30|1X;~{n_qta zhJKdN)0?2D{gs^X-te}OcE1Os5w?hPE4uE+TLJpjGsJ(wUL)+yQoTkvhNQt*;b=iY zgPQvDWthV&d_xQ6&-5j(g~e4mt?0knI5~=Y@BZ82{{O5z{(JBSC(KiSz|#9{n-p9= zFV3-fTg2smUJp7uJ3%fMq^v+En-|*JDZYDpadB}68$nWC!IW%;#~6_A&FE()m9fy1 zkF#9b6-&yx`|05&Q(Dihs*Cea(4b1owVN-!$T9VkrN%;nc}c|s6*Jgh#Lf2XqIw(m zI=Aphrcb8xbic?NXyi2J5z-eNb{7VCVZSeCMyx}~sj|Cc{V{g=jH|CY9xa(%R=r;e zYk*gZMoiO>jh|weZxq%>uI=qtJgRP(fkqQ17EAGtYLYnLNb%j*aB&o3J>&ch%f7AOY{m~k`sjtdaF}RC29}-7;(e_ed;_-$%V;SW6EL4ZLnJB7Wo4w8 zu`Rc@AzFAhLVNwBMjPotNKNWNi5}|!9giQ~bxMbsJYSGA_?h1NOmhT&uWywkx@p^~ z?GwTg$woi~NDyX9G27hLo<-`)b2bAJYsdAY2|GtM=#!%Y!8dFs1E>2iBt92inQ<8= z?(LEF`fAOoI9UQM#VfZnqt2z^vh%Ty~>i+VbtB;Y)k?L^BdCw(n!bJ|8m!6trq zv}VKdh_Kh)OxJAsxl9JRDhQ^?Q-*<(2vp}FogZDolFGkYUTs>Rg zJbD$N(5Dc=@`R4>&P1TdoK?*bz1v=d3!HQWfrN(Mh1cw%oB70BG1!#a;Kt7h3A_}IQ5apEfD(2G>h0}GH6CbUz zh9uT-$5rVuxaC#*2JGE^)OkyTc1lNys4!GiBqExL2*wg79g@MgI_Wu`fGZC|PbGkL zM8h!+2mxP=CBq|-r1~%>6*2);xpPn^9QRgv*(NY;^|&5pcx*MDfc6`T!rlRDc9I#hoh znC52gLpWt>>!f|pD5?QDIIaWlem3s#v{sYAipAMF?s*?3I3cP|MOa@%X`9_#5-1ul zOqA{*H)BNJ7*e7vJ|#8V*Ppi9+wfj~j~+YsPW3HyQE^7D#iTA9z20rLg&HK|9nN+N zE#V>N-rxX=WFfjd^_dV6#041U35uCq%>OSL7oX6^gvQRz3h`si=^rl4Fqa zs~b$Ym=KYYjG}1LkPuOqTjkC%o{Nw50TE1%9$)s^+iV`Er~ap?w5Qq#QH2u8g05BR z`K|3vC9KhoI1ho|oQsEk>q2jEk;&6-Ilc8tzLWe;UX*S-3!cfI zy8CPL41;->i{c}_O6^ON3nmfM*yQrX@K!$D^3t6Ky(W7cZd+kc+}wkctZJ})w0jMa zU9PvEbXi;G&t5?KKdp)lI)LZS5Mix>aoeyV7P{>{=2@JwT;Ku`($P1b#RF|NHwQ4| z1LZQI(VqK9qgaFewX&XSw8)%Jb@EJub48JRo`_ZDu$8{k9S;kN4t|$TIlI#MzN1f3 zr1s)c?x6{9z&BQM!;g1yq2^b#w401gvb=XKExI9YOLu473%6@8W?Rh=w;c3XPL3%> zwqxdI!297=iq$C&yF#WX5jUOES}^?#;CzEXS_TX3?tn&0g?=2oRw zzYS)osA%Mg3C^if&)AqXwRaGU4YEzb?j9DnAA*@RSQQ;tlbo}1=~6o;#x2|2l#BbR zY+qGQ@q^A{tG#Aou@;rsdNTSX zq8bI}amx(@o@9T%=C@{*eK;tt?!7uGMt}PSmG{QmPABCZq#$nS2c&KA9s zR$vh&U#v^^U7YFe!wD~VsYDQa$d|(Iaz%|OK{WG?O?|Q}m4Oxs?#7FC0afcdlB+r{ zUFc`xE~Vvq^Yz-Xv^Md=8%vK_U;y?mQ^AkjqfciPTJcQT2O?+w+4ZrY(rn{gShD*k zzEA3m4;aD=64WsUTHJy@*}%4`OGkez7gkn2Jm#b;IE0|i)w=M~tC4r;~Jcb^q2--g)#oj1?_>U>-4zKpu^-S--8;JFrqFtlU}x?_q1G9878IcKwM4rZa>qgIqmrFS5_LUdi6$ zL9Yj|Ryc3SKWe(ZYAHGCE8|vV2#?!X+kWH>(cHpckIm776qzc$2W8Op4ewsH6$^6l z7Cr#ki07=XG*=pQfv9xO$rT$L7OqbB;gR2{?y)A?Uow% zT$aYAAraH7*O|GEn-NF0?6G?>>Nd}|ZWO@lDZLy>l`nYznu|u*T{YK5F@zr@qJi5# zcbVww)q_#4ffX*-f(p!YYGUIx%v0lILiXV4iK!ELiJwEml-jo$M^sWuNh_H;b*{2;Lh&LC@zIo) z_S5g-Vd_t&ykcS@rnGB_}5fCaW^E z{q``5i;uSzPM&cUy%l%`=!vn1e3!=!k`~K+73_^sV?~*IdQvy>+LY@9b%skoDa_uUL{0;U?}9dl zuh^+{b#<9p+Z4l%jaPhqeZh14ohrfQ*tJ@v zbW}FZ5>#vpbVvpT6H`)H(Q29ipB~={id^OTnL2rw`|QfauqnyOS1XwQm>3z!4VI}T zqx=jF4I%NJ#h|eu#<)#T6-2kdPs?fO8XC%CcY6}Rs(=@AF^UJn!Y*s&X_Gd+adadj z>;tjH(NR6nG*>`R&p8W z>*_UQlo0SJ|LIc@B-gKN=4icT0N<66ocsvY@iIpXP&yK_I_BoA+8#s;XTQqn(G4_h z2LWP^R)|vO3lL|AfE22!x%t)3l9BQ8m9UQS@o^7f2BOQRv?cZR0OmVV(S2kU<&*X+ zFZGye7u*~31vh5`ewed;4tO6PzN^L;0^S)2L|NB!hBSiB3MLB{4Q}p#mpuj+1%b{Q zfHpefs6yr3jk5I%fOv|yqp^tzTWW7UYcJ^nZ&On^=pdY<#c@zi{%dM#s=`Oi3keI+&UMVfijbL+zUpQJPTpU2Ir zB@ZqN0+AZK@(>7&5%H2LP(H&2O~%F(<>2Jxc_LG7xK{VI=I778YR|l(7lVSsSnSQF zJH6XBRhKK4DWG{O4O{$ze`F6$>xwmX<2qW8yxShog7LPVShk^&KK2>F33|V9OX{EiEkr>+2=K%8U6nfStWu)9lg( zCMRP0TP_Ef6L4<8z8bPCpO$gNu|}AKy&kKS>E@_9xbbXV3>h;b^J)Z=Si9;;Z-fQi zHDw0{9dKFt1yf!RE`jTlZX7t8*5>8`hTLrf<<-Ch>d~o+4V+)5p;Et###1*4eKXW+&PoE2;jsK*C0HM1%-tyFp7w2L+d7RqQT}2 zX<-?%yEiBZvNOvELHY&q;2dB*sHv%ep%Gvmb*PwTYUEuR39!@yhXwR{PRingLKQe- z({=JR3Uq>}X|W!oV`E@~!Ke%j3_!ykD{E`lQR>CLaww_U(Qo?A4=)mU#(00qYiP0hhA?G zH*H$0lZ5!Om|=SEmE--s0oLt^ixh5qqm}*%%7X8{z=NMT@W|#+U1d%V+qT z(sC6!e@l8|p>1mFazC@=&koJ`mqo&%Iu~-Pq2!>NV0{*f{0tflaAA(FB)>LpO~(A1 zolk8+BLlYv7{Zz5>FL;FER|+CLWsKMGt8T|x3?JyKu!%DbB@>>A1=KI^8oBS7zZ$P zf~w}=6!&i5X!h4a<@Yq9NcoT&$>T zb;Pxgrd8$)s09znRBK1aaI4Z_Q`*Wfa|+DG;RX}xAVMm$wCkN+d& z`rVKl?&Aue;mO_n5)$}ebEV8z3YB(#vb(c9#V3j99e`H7C>e++ngEa9%)y!8QpJ0v?t|>I3!Lr(aV!okk zU?79_055y7#Pn*$x;(K;j0j-g>VAJh*+W2R&jgu9t7Tu<^jIa2snC-I$N5`jNj zz3$-PlrG#^x3|MI^*3(@=*sv^@!dK-ElX0(#R>v@34AN?G!BlAV7J4v2f4Vo+;=K* z55TX*D=>9+&J_$-US@x{j8bHK@K52-OsANyr@wf-x zE{4w1;^=n}1_rFn<;f6z^Q?ze>KUY^#r9K=r2KZf%=hb`idU&K3!bL4H*P-z&Jo-N z+g!x#OIuo6daB@Ud@W{od$+~5!CGl>#EQ8*&(UghDt}q37ZSS7^=#W#s}eR!XR*-_ zr!WxJiKiAnV-IdI!dm+Jq8)@g|NK$1R*4o;0t>2>H|g~Nq*kU99Ld;Go%4yQXw&KK z2ASO@WumJn3&N4~z_fy%feBkgDe zrAProfMSEWb1t^2unulQJH{)x^32IWu4!rv{KD&|h!jN|GA@s<1V<~QKV*k~=K|s`V2*(2OPPPz$$v4(aRrJ{HaDnVKuo74aGc;*xXqu5R`!;` zvGY>oyZn|ys*~deFSi4_dV2sYXmn&`A^$!_t%`edg(DYecWISn-UO4(!aKpIwwehL z`%>Af6*VU^Ia*6I4K+f{#X}P!S)&e~!~Gp%Z`?{1IZ&3qj)B$ZyPYv6N4K^X`11FC zuFF_Iu<-J@x2_-7&q#ReQZVmzakBJu6a)kkRoEh6!=%ARg#`s3TY|x4Y{jpp2BXJS zigj1=lYzl39DKhf!YcYb8>E4Rgf<7EoxO`SJz#_(>F#4+n~6e0aejOqWOJ_7%MK#J z_9zinJ!p4tFRI(>33X_he!=n-t?Hmybt%{)CokX(n!qC2mkteS9~~Wu9g4!DM@B|2 zEzDpj=+%Y;gSpxE;zwkr3{X`S2*)_3OfeS~DmnC51u=BJljCr5s`3g5X);iV)e2L+ zIPp!m899iJX+QOMTy>upj@BJ^VVDwGYp%j?TO-Ch6XN9XH+2t}Qu`8WU&QoKG9qK@ zC;8@RsDsnLh(ze==~e%J(8z1ytRbwBvttp$XI&z!Je2_1AH~Ee4qL$t zlk>YFu%$8?ZEX;Bwtb=`duvpQ>iy|hOW6hqGI;Ew5*=h;Yy6_0r@C2AljCzp zo?v2Vc2Yoi?>VBhB8O_^nXR*ufj71S>?B(JSf*_(HCLKrENN=A2C|t$PxR;!v#S8Mk;(|{2qp+s~L+Pt~XcII*RDALCzk6tfnAy z|17ZUU=PlCW?bL{;9DGc`_jO`K(&c{{Q}Rq9dM=0YyxgdUXz^%f%@uH{^jH8XAhg07|i1U2>NZuEP1Vd2|AE$0CT*@4#;H-;J+7BK^J6`PcFKY8MWO zrp8!RcMX?I1j$~laq9wJ2^glmFU_-HvmI79!yPZq*XPVvIjGd-9%nW_ooJb*?%v0u zR)l?V$)_DpJm=^669qG~lr6n(AOG1l^xGq`kdOG{x8h55Rlx>p&)8r}d#&4QTMTR= zCp_YI$5;s>6%rg9UFQl{LD~G;*%1VO^TctAGTPA3*^fIo)_Xc(g2AoCSk1@5j2vic z=W-}3E29$xf`hQNTje0EvMZ3!diiE@D1PMKV(5=F^$t3Vov6yeohyH^Q-hwh_~1^I zM1e6GFmuhq(Gp2(;omr`wC2L7F4npMC2sE7uLDW(9BUU+v z^Byn(p`oGJg6^8>gl2AF8DW{P&}T~7gIzs6o_l7w1;QzgnyK}_{;UYr#J*q@mzEG$ zlC&(Yt8+K<>v3Ut-&3EEWec5|*V0}+$brCdXmd5eH@?0g|1ZAxrA%~`X~{Sl>_}(B zS`da?>Mt=Y65vl1l zx&4inD4XzmW18^1z&Kl<8}1qcbCT%4)L8;9l2zP=s$*p(B`kXD3w6$pC=e7zFe$I_2X}JD-U6X)se1H^z#3H>1aUFlRfV|G zX~h$neaY#Q6CZ`EAUd&b_$Hp6Fak@*f;(zi+20P$$6#;2c1mIeu?2d>6N8>h9t$51#JfC)`+QmH zhhQrlYt50c@#N+yV4y5YM|)Cq*6AJxn^PbZGhcz#_nsbu3>)j|EgsCTG3c31gZCdi z>+V)%z_yfe6&lxnbekk`=;^%^o?^DJxo@gKF=R)4s9)%m?b~WW5FYJSb$DlM8w~CV zK=Zo75foj3Utv6dTY56y+IkH{(%^vhh_Mx42Vi|n>>LFtt zr-`|MaN@x~czPH^wpPv^Vrk$8w%kArx!@d~u{z_#cwKu?Z+zTrqghn=HMJgQ<4T!Q zOdeU7IeEtS60M4mzlDqH`+m>&ODSP$#gtg;TMjyQT)u1j?8rUjPyHN$qaN}oujT7+ z!x)@OrQbd+a!#7__>W!cIn#A!K-oOsmxQgCQUWL9Bh3+8!!7liBi8AiXJf_cGT4Vg z(GnnM0V~&G(;-WzHAWn1{wQZ5YmrS7Q8wMV5sC$lhY#3g@S{htI77|QzA|TsUMuw! zGN_JBYF821nz^2{pURBxep%g8N(l@ir0wg|!OJ)bNoBZR5Z`D5V4B^%VzWyS=T&}ler~rlx zV?g!Ji`xsxX?TX2M^_04&!bK&GBY#P2>Y#k9b;U<_O;t?!AQjvlcjDR$YJ$_HQNW~ zUlopk(G2cD%gsd?aNNw-fTcuC1v`PWo;OtEgk;y_VMDa8dM1OQ#U;#A4}DrTbDyD! zw@+~O<=-(xsYpaq?@3qhc#i@;^(ZIxXgTBNlkUyWW+wKmNJ1RaLrpagk#=@s};GTIa3n=-Q~ zkl00L9(^LeMF=K?>}M|@d7P)rETIUnLiEn-fe1(gL0qT97asYz?>;E>feT(M%V7%e z89N2GNoacu{zNsTN2S1_&p_m*MfaL*1H5N79?D;gf9{q9WJH|YKWG(_A0}ZS)8*K{=qGGSyCP4H59kN0l#3pUKee!ZgL_a|{wT2$zs+3T;M4%he;oui z^8s9s#W;8;cm(U&!$XHDlA3vSGb~Uya{t8}M(@>-|%YqXr}sMxu&}O6QS&U0J%fI`dO9>I3XAkjV%s8TxcaEB90iRw z^*5xuk8J4{?TIaFKxw$LMyT|4JgQ!C&M3Vbl(K83P=~0l-I+Ii$)j)iTRRReK^Ih< z8A?&tb|UPHtUT?Xr@M4WJl^Jh!a9yODWYkE6suRJ5V#751Pe04@h*;)7(!RJoQAuR z|CtlA)Qus7l9Dp;AD2msQ6ejf=Zn<2&Q2PipqzZLb6JoR*}{W7v{})F2>e@_h;e+8o%T0Nf$DJQ{fnH0(r{I1m*@^}x?Wi>6yqZ&Q zDmg|3h`pT|23JWu^^@;^^5=rJKhNcTZn_2O&s0rcx>iQdzP0P3vR}7sjPh*b#7w_! zO4=Di@q5ouR&prTtBVm7Jl{DW!r-5u)~sf+ZYERvq!!q+YZhc`y zzxg*lEf`Aj&W+}Vl6^bqp{Ry5s-!@#S6nRX(5#cxP+lUaB4PY~yuRugVorgpSBn?0 zwP2|WRDRbv$Sykr+Q%HERX*gr6=&*zdmE{)T%WpQUa7iTCcM0-iBB3WaKS7Wf9LTQ z`i5{EmN>6TEx!DJIf zN#)m0Sx_l#GUrkRre@x0e|*i!%@utyr20zeHMJ9Y_}2589_58)d<0C* z{#ZT~#Lhwx_ej_l4)6WNCkxKl7i_N`&Kvf5+2CM^1tj&mW}XZ*nSaZ{w$K3ozpwlF zG@awt=p+8h$@S1A5qwBv#2 z!22}@H;Oj*NbPm-oz&_pX>f3>Hdi}Z);SDZJE%3F_nxMG9QP$ac*H~SNpm~3;_NZ6 z(C#&+(N!7LSF?e+W@^grl{1HRTFwyHfD|_2@jQc?+;pXDf&DlC?H%DM0 zM_+6J-qtbh#0p-w>kZgY7`^gBaVXSE_Z!s@chA^eFaY4D=AWV$uz{-{#*jWBTt;Q(_-KNuu%kP zUXD`_Z#0og9tgjxz5+^}^w&03UAyqd5d88m+O?~rA){G#k+eET;CqQ)UANqaEiuui zORz>kXD4#;SsL&CZ=QdoJaKkK67Fq8c)AU5msK?ok|9-A(vH__S0Cz`@3!8OmoQ&1mo&Cr#O)q`5O!N|?ctzG2G! z#P7UfFkJ(-FoG4tnTjtkfYHa;o4=w>{M9+rpH4eu z>$L2jCGFtR`W;c^lYO=_RDj;Q?@ZkWnf5NVX7esD!bU{X7Nd|?Ala99S!5qpr)lJ$ zr8%DVmoE!)6|Y{{qEp=7K7`BYF>*&b!gqOpx`5{&=E(97kf0<*BVxv(eng#0Y3|*r z1})|2Q^A{4^7r9;S9)4m62~t!IU}VKi!+*YKQv-f(F;b&yM+x1w{*OQG9l>n^jE;-)2VsI>9+=R2!wT&C$tIywh(aWMT>L2Ki1nJrOHh4a>e=Dzw z7&fptmK!G$!hE~fJ+`#1_3&41>c6Y&ejl!@F)ag$t`DBPpVL3TjJEOJLY1A3N)9jKtL+{8Unlbuo;ua2%W% zVfHz){YyCa?XpghuGhhzMcm4FzvmJB_$K_#rG|#oZ$**cUNU!C+!(YqYhu>X{?7hl z>sgE^edefa0ahbV`|qopj`k$GV~dUO@d#fI!_cIT26~a6^E@XfNT)B#B{o#P|Oud?(^>|5D9~yO?Vg?VlivP zBl9VU+j?Iy_|QvNeoI@PM*5*U&*#ya(dWI!){_Jz>5Dfs% zT6F(nkbJS!ZVPxupyiM}6CG%o_ShBZ9dY-8SEVa0GArt#te{`0mUbntLr=1uQw1ta zz(9{US1~ryy)VsQFU7aNc0qqRMSkQAJ6>x1oC+?f6yH7q}P{xE~5(6O}sa-<# z*7+Gx3B+wr!7pNye3dZo{ixS+vGPn}`}~w}r^Yb?xlWip*gs2n`}aewGeV;oq`ysR z`9(z!vyjdgdax_VL)$6df8d`OWu1)^#-Uz$M(YNZ-2-h>twWJ#GCS@m0#YYD_fNCd zFX?$THH;?t#&({st!sLnxmol|{T@A^&hC&piQ%2W>y~N>C!S@dn(bGITRdh*on+B@k{BK+HG($$-innXM!$=&^`nPa?1}D5*8^e~q(6rO0`$Iz)YH>pp0~R+=X@cyu1nXEAENe=P&-y6jsSm98| zmTV-SUmj9&*>gT4k(WA zvauyWvQ@`n#c6B3kBLod)Nx@7@;?dZe&c6;>He3ydVOza>dJ;p8}K;Qgw)6;eG-2b zCeHssKv@3xz@_obuknRHd;BA%>|o6&W=)s0DLz}UqvPY7OT}^E|hI7#bQ=_a}9v5 zlm?YqxJsJkF`;iAP!o*!rjG;TIKN09-dR#M`DL7xCAy!)eu-m*z^8!uNN{@Z1XNNr zNSB`zocDIj!~6!}19eCI-HRk#=f8`-&0SMuln8QXBes}IVBZM7N?xRs(0yj#0WDYn&Gw<&$>k#^Uvl3_O!7|uw&I`NqIlA})2j!uEVDFHy~CwQ#nq`& z5qpxDhCMydW?ONuE90UiE#JxCRL~`sd3kPYd&j;Ml`)PR*AEq+Q1MAS*xo>s8|>`;6A4Hv9i zp7W=_&9I#`m!%@#@VOJ9!}Q)&k>veRH%CwFRE0BLN+YeZ3k5_H}t-XdlXH6tRlISYMGzX7`H!B(H*W3=vpP8`bfoA!_E2ZZNEhLH9Gw`YQ5N4F@dtJjT_jhrPIkM zJ?-adFB9+IpM0<>VHMHNC3}R~7oR%qsh+Q6(|n#-QZzF^8K#Cx5>?(*K&rXT-bNP) zQJ~n!zmb0i8rIpE;*X-d@_RdNHExoT)npJ>E54GevYc=rA9Vv4E)ze!Ck}u%5)!^h zXOK)*FSzDZt++s(P%XWZ*0IJ~En(womGxc#$TmgT7LNbUb3#RP>_p|@y^_aPITvym z5;fJ$zPl=LUrSnjpLX|%@q-^8(kPTj+YuIfJ5tSxHRJEaq;6HC=mv?&(Wmi}XS z&UZtO`6qocz9ussHe3_mf%L_IN3}dEE-FD((EkpJpQQ%;__eBGM2?YnU0^23%skgUfcS%yD_oOnc3%Y zTHit9qVlzO@T{5bt%CfGwpLyf@0-i5WMTTNXTBKmM#MgGVyfD7cvznpU?ByPRH0A@ zDAdP*0Q|A`Eu%qRI7*xN2j2RZ3v=@7M8GQ|m$2*Zc0yg@WIKU!>747|Fh{p~bb`~= zNS;On!*R=|wt){r>~)g7#7B4CHSC}hwM>gnMEx?-J1_t1&m9RWS#r7m{2`XUL-c?D zoh$|=&*|yux{XGXx|6L=Qc}_{-B#6pr(#77XJPpI^)UvO0=XcHFKkD{=U!A_V>utHpTB6pAH4)Qulec14xl` zoutq9^8}q6TIM3pVg{56S>@iLTR5q-a-ZaZP=dvQfQi*kX+uCFeatN%qMQkz@YVsc zF8{j&Y}{$d5k#|>gD*Gn+E(JYc%BM~JbNJ)D~l@EiIg451>H#!79HTIJ;|U!#jN5W zw!Rf27;L3MdAuHs)(&(Co3E`?Wctd`MXGp3MsXa{*N37133tC? z9c-l<9H%Hr7Y#96Qbl=Hsw*l!WhM)i+4Rk z%COWgKLrX27TXJ-ey)~bRhT=F1MT38%B0;ES%Io-)E^~FzrPj#Jb>mlP-27+NI=`Z zEnf2$3rcCHxc(3{Vq)E*QzXAP9{*gv#YWIy9rkB@%7>SrqdhH=V zO#TO1q|6=Pv@pHL5OjH>hZRV^I@toNv}0k{yObQ)H5JzLjcuT|H7M_u|AY5Hjb~!- z+VHO%iPJRwD$DIH&($saSBa#vRY&r7kle$$z*a9*1PF=jjr{rhAjM*<^32>0YLe|a zdvCbm@ZQ&c^RBaQ=8F%}Np_#-~UBhlNp-7qX5t1Qb`SVAijGtX>rEH$sEEdW0b{te|$Otqz#(LwNZwBXEeO4&8 zny=KhCZOHyk9hl*PubRcndgQHkAb^Z>YRBSQGnguHH<1Z;pn=1TCjUP_iNs3_cWdD zWA=^}42v6TYVkHeED2T6kYQ!H`pmtyNBs{UY4BQo@vr$P6Z6b0>&J%JoFPb`M|s++ z^}D-__}l?&S@fRl|9Zk`ak4}I^#ssk{pZi#8IML>h1Jl()R6BNF8z|d%jVllW@2o^ z;z!-lG>eFg8-5U-$o}!HjjX99#_!6)#Cu<1&V3Q+^SVxbByZ1$oWMjaBCJm6`!Um? zo68|9zO4^G`*g~ZFt0`3YUFWB&n{u5k%U*NS&^cZQ_?p?N6(652EV{W`uUaUQKWQ3HR@dI^b_~mg zX*CT|q_9f(e9X=tF~}%rbS3k8ccq-nS1XpnufLO-gb`jyLf)%Hhqj(CcX6h$^%omN z0r9WQXMs4%iw>5;ff(_jKVX{_U|G|ZEsmxWpIg72x~Iq~2Xcsh(FCmgw+Xfs1Fq?I;iRImE9;QnPxmZMk%mZONT+FomUpxRjyQ^ovc_;dH3hy%!7jJl(4P@u)#pSwcF1Ey!cf8XU8~(d`JQ2S-A>h zNZR%aW+Cp}AVyl$U7n@{!>+Aw>yn~SciknvZ-wU0!r{_W-vw=QZb^3<&P)*%#!|WA zAE(!c?g_-L_FfgC1++$znfy^>0~D6GU4Dbb8@CA?zx&^MuM#M0(pW7)ny+Jz-B*uy zb?RLx;6Ih=nx#*!4q;t?$q&hU!5Seg?LMEt@oD1?w>itTMW}ZT>!!=MdG9!oR4M|l zE$0<&ayKzK5GkOQgNs&OBU?}-Yjct_q~!6NIBi=X{!MJ6aCFk3%Iyt<)1xnMROr!V zgh#_rzwL#Ye@6;=)Sl8dY-0i*Ghh|-nXSe&&DR)X;ZEtNToHs9;*PpHL4B4ZAt7N2 zvfGqV)RW{U9OnIPKzE&o0Ox9+emPy`qwdDds#(S*?dhY{xl4!BCVe!~AxX8(4(wzh z`#;{hUb)~@uQ?Bc#KiW@lkylHa8V_HeM*FfZ_ch@J`uT6Aa&t2U@~XBmmOc{utVIv z?-NKiaro^~b*+c3f5xk(*5z$hu@~udWa^TL!b7fN9E5);Nhs{7x;Nt9ive^6#FT)G zPJN)XLN#-)ACWx4{Smo;J)ma--O|6F|1?T6ghAcmx*vf|zCh~Q8l({bvl#|`g6dsF zJP90tAE251!vQQvmAJWy2jR^dc zo@9z)x4EWdnye#VPV_koe#LGS4Bw(2+(TFOstLqR&;?2A`7~QHVX6p~p)@95LHM98 z1F*r1c0T+Z$JP<1u_gwRb(&wW9!NyW6GM!IiHC}l1ktqoKrGS-F$cIKtbX`ipB6%W z5(cIUR5Yo(DUv#rEwLK$eH$aIjdN?A1IPR9X5YtV8p=>$4DK-rE6{=Gt%|X1j9MW-LhW8!g>Ij=ex-lC8ke)u~Zr-b~>vB zp?G-lMHm;{X?eBoY3x`kG-7HeTaauqf4)BQ))7tm;a|;U972DP2!->6XJEY?WINToKCH zg^nLQS)fO`db_`!>3%Mg+KAk2u{#c1~Db$o8IyO;M23#Q5Co^Zi)2; zrUV9;t;a9yVbFmF{`NMCv^M3{y`mXs!AH5WM=+DD&Ff~m$2i`GDG_JC_$(O%jmeP+ z&l2arjx*{P_MZSwS$quktcJ^*D{_v8V&HEG&E=NALxb}uYi2NtcwFtL5T4R2@CSZz$Q6umhBi>|0}v#PadMKTVcg}7>Gs3 zhtIbxkqw$3Di1yStzJ_Jj4*-tjbx=DoxAP_Tr$zCe=kwBpyKczZB)c3n~81<%gSds zb}+0rGaYGz{?pd%d3!$%+Wb-D?JTw^>#r(X`%R1=xXZ%cuzN?wM)|%ehBLoDFKDo} ze_Wp}ibclg))O#e{GVE%GCHtREZz6w?(cfWrI;$m%E}6GYsG!QZd0O%3GH#QphT)q zC|AsbvBsHAVJj3J4%YZ&QM?#J7C@2tdWK9G16zcazH3=Pf5a%7hTkRAeESRslE%jC zOU;zjf}G0)$FpNHlDr)IdV;QM1B}tyl$Q2{60wrHLsDm3+&Rv8R$k!N5v5ZF&0gCsv*)`-UNI>5T5~A1yd_HdVvh}2Td>otgi0memvNa8AU2O)? z5dt(Gt%J7nIj+kJHr4al;JVp3)~C2kXx0SpzlvrWVO)`%Dyio);G3~MeyYf+VY4Id zY9@d0Q2L@ctKdEC#k~NOQj@5RZlpknY-V-yWwbQ23 zV}J|s%4U6E{5|Qy^C~PcjmT#^`-zb!MByV8#1@ceYMUTD9joz?BBv89eW)lNm}RA@ zEtnyb?Ide24u%tQEDe_iC8H#SHMcJ|E5FzipVKB=AOCi8u6j`j>ZR}=NX-pd8dF&> z2=p%(!B>O>vxL3th-Y(G48_0e-It4fo^pSkh70XgO*kqR zfC@2Bb~tqDadk$0GK`)Ee=}X=Mvo(N(L858q$6LC1UZs#>zilZQ-^@fj%}8Bwx+m{ z`qSFT1S)!7Nu}#Su*!4QQO%aQs{`eTjJfn#DS!^0P_14E4D_Hx{w^iV7x7S96nOmolXGD@9ZeOegZOlzufFKTU{RSn)xi#IbKO!aI0u$ zTxiqG)?UeNRCAMf(AGv|y#BL3L{oQ>AnE9Tv>)+o?t-_tlZyYV!)KqClSi16QF&A~ zGb!vydT=8St{r8C#f-WTFFFY`>D@Jbj;nW7Ye|U*<#_YWG*v`Un&66d`WOHYXvMuV zzwU_>Ot`QR2GCO*ynYy57HXh=>PJdhj^T(-HS^qeukYa%eeR-%_r|(fBpyMg_4i$^ z6XExrUPEIYKeeYG=OTvJskcDGlI=`Mjk#SgU>vV2b?6aq6|;DD<91bf-q+Z?Sr=`V z?4BRKDSWoLSSfX`(#GC4?DE5_xx#kOJb7h^yy2=+1U@9>?hl+sTswOkGeT!O5e|Ff z$Mw%r>`!yw=4EMDCM?vy2ykJ8mri{2&eAa--z~H4A9JgW@3IZ2wzVWC-ThLmi_}zR z@QDD^QW)*We;zO`f$`~I&wtNL;OpV9LGTM7IeIRkFun^1v^;yUHCLQGnWejo^dE0` zlL$N#K$Gr*E9MUo54V(Rn6jbn{wK{$V*hP#q26SB+*txKymJ#*^76j*E7^IX%1zKa z$J?7PgQ%9{|$8x~gI&0V0! z60b{})kk3c-6yGi`g^lGyiymPPJIQ3v8;&#J7Xukt?r>4xdIi$c)vS_6S?cbf zVhj*jMtz@r9Td(#(&L|D`N0sraQhkeW%G$Y7mkrEqE7-m6NGVjMnxi>ZN*~CvKZPPc9?xIChw%Amf0R@<>~v`lj=zf;G6LS8bdCSOJoE_zRxt0Z^gp0 zOU|uGv!}3+_cOWCX-ooM_RtI|0T1w>eeOyt0+}3jmX1jc&mw92 zxw6@(5wi=@=`6T={YD^CG?u2NhxEi(vc(ll6D@oiUVy1~xy6Rb@cRHO=6zp+nsZHKd?uXdL3MB3~%X1x>nWv1=PAK^vl6~X%3r#e@y z`cqdobaB)vW(U=`dRtipv|sCIHo+hRqRRoyf_?B+(uY0DtN4lsAT>OE_W?#UR??*U zeuLSP^K_(Je)$Pyb?G0W?*Qom=q~T*lpJXegKqZ_;#GsD&kc^fb=1<*KJ;u?G^M|C zd_^ZYT7W-Vg5Q61DRU4SZ*#{@9Fbe?-Hqa11!J;jCtes}&`qSMVin@l0Kg;R0{a$bj-*g!b(oXlLq2l0&O_y;K zXLAoq4+o3upV??=i>gj&tD^C16K2L9=`>`ShBvGxz{|%InGZAGzeSLXFA0 zXw#=FYPmIpRHBDICyHusbf-gLQj`@HIywxTiBur^YBnbnx`!&BtNJt0|E}F*XE?+oUEYc^) z9t`3Cm@t1CxaHi>AmBm_S6xULf9EEcOYHN_|HIFpBH;y?!nr_M+rb!I{ z8FnwG$L`o|=hakO>DLiEOs{w7aMzRV=_!O3@A2|&(D;E}azypr_|Q&CZn4mRi=BK^ zA)*2>so&Km^e{nkj}`r%G|7fTWN(sQuB9fT=2$QRhyxC$=KV2wQHr;RUp1j-g-QsA zKs;;kgTY$~22i~*@DFc@@0=)YwjXvbzvKYew+6>R|yHvXRlP8n}H7WRgA`Q`2#k2!gLen{RkmEqI{Q+5> zj1lDgl#5Gzq;SMxb+aLHpu$>oR>)b$IPR-kzoLmb_J3FT|0@3f!AJk8{nsjEV55r> z%=I1s75FX(_B1)1#r$Jcb8rL85Dc*KdTv2aT!(@%{i!xuYBo>;;F^+0Zs$!yz}b^; z&Bx2@_-DwHAbK%UT@U2e?2P01`d~7pC19`~J(Q`4)}K*CIB#7M_K9cP;>62Bp70|W z)B1>&h+=n%FKJaLM%1bDs2a`g%QrdqW4<|QkqMyc#{jt-&Ca}{I&q? z%$A0eY z3+!!0U$6}|;>}E7;}3o^F%S&jw*a`-HfVi~Hoa~evSRd+T}Aq>{ACC2iAnxU#+dxb z7K)7a$GD3^wg8U*EO7|7KfhxK9e={Rej`|2coLmwE*hR^^J5KSl5U<+gV}8XN-j6@ zjhv?PigNkmGyulG){+XB;OD^bZM#`{d$%8h8CNcvMy!f$-a6L_gm0R@#yLBt0elPg zQ=j+HfpyROepYCuujCEzPu55k%^fn3%5PLO(iDf5z-||v48PDer;M)&{Ps0y5oM`K>k~4Nz2F6-=4w6-<%E5Sg81SV@yJ_P#SL~5n-v7_ zDEr*BH2k*HYj&alxs>TWpCw%>A!$-S_jwQ^;7#7B34*Jh8rx<>vmlFI8r~BjH36WJ zV{m!eq_mC^9ODyh;kQWl{?hNN8L(PqXQ8*`Zw%FMR_1-?cdLXRaoqgTT8keaj^hZC zJh#nVeM&to`XyabZe=NMtfX-~Z53+NK}&tRwrpsa!+Q&O!k*NIAPFANnrTy3B~LIL z`UYuQM~#nafW@w4(JZsuc%n0#NRhw2B9TGV_YNag9#>UYgG>St#P#YPBUW3iJh%oL zH9pMS9t2=;Dk>0mGW=Eyt+s!x>riD~C3dyK?H3SH5VJTrUZNGKE_LcT#hIt=7%3AOSSs^$B>>@?T^G7@t)o0KRwLd;w2WjEV?xQ8V1 zU;OkrZKYl$>ZQMq$;zvOIkIDJ+43BUD|!Lx-gnX*@zVl7WgO@C6bS!a@vXo8hduED zEYbhm2*U+uaFD>6CBiYVg_3N4f`ovpfhkF5oz<+~AIdF9?ms7XN?y6)K0_tn6q>I5 zH&P?VV6a`PB0m;xIdVMb-qW$h4`_3Cc&46VR>iLnh-l#GYp2FxDNtujT&Vc*AVNWw z$;6~}yIn3~s1kMudGA8l-btR;GqbJsK;5H{9d2x0=RCtT*Zp!EYkPXEZgJW(&hWNc zbvVX+?F*tf6WmPNxX8*e6qN_l6(Gwff0P(LGOG9IYWG;Agn(m@zQEproMLu1S_6E; z$)5op0YqC;BA^ey&D$e5iis*WylnoE+?VvV!)$(`$bnbH^N|B%PnaoAxLpt2G`h`~ zg6&bp}0xr6p_|q4`|bL%cRur=cjt7@Vx#g$XWs|CofnY_?H}X%hkPOE{9J zbh9F9p1#G%G%L^;{!XGqw( z8$C65+PYOV2e$phhVh6kx_KZ5S2p1%eKgr@l20%)B|z*2@TU=ncU=33UW-@{r%fDi zDuCZ5EqQw%fmF!FTfmH(5@=}GyCjWIi{CZOV=9H}bh#AU7{A?2x=Ob{CD%)Pp3KGy zMvbSDdNL|dcca5a!KY@f;Jm87F}k`U+;V0zaFHDjG;Yz}CvN+kEMUy119gK{4SMdN zgQMtoE>$DdTy}VI%6_vp^dS*&Q5a}+myf3zB;R$?rZc;(SOZq|5^Ps4M0&>oUW&XI zn#$E}Chc|nbQ}KA8NupyV(_D_=P#ui)uX~B1Yl<>$9Hv`y@J7luCek8I^x7cO~?Dq zhHZTWajBBW%C>~j_drsvIxFw8L>Yh#JyKa12v5XgJu-S97*~Xon`bVD&YH~9e>BNL zIu;5Uz7mIY_n6Aun-GelG!7)&zVhI~#cD?r<7FJ@56EKR(Wo>&jQ7eQfT&LOd)~}# zHcWJM^5AB(GvdlE2>Z_O&Ovf&PY)YU&k<6)MCc4$n}Baz#em+T?+9)(_70NA@WW-$WXwhr!HkES6V-jgr?ys1vFD5if|L2%T>`xo`;* zs$aGTj9C9J`ITD#-Ru810Rg_g_$2&s&-M-2*E>Mqg0~xa198-;i%##!fomKqWEt}_q1WVSc%)mz2S?*@k(&aMG)0cW=CaArkAS3h~wxch=mjcGf9$| zFq(GW`pa{jAO5`YC4T|_{79e2a%da5ctLAYt2|kfwa)s&m+(!`7a1-ob#v#CuC!|F zC&&(mXCkCVJBwIuwozdHs0gpp`;FJoXd1epv2rKo0!{7u8_w+nBliR_3t)Ttq$O5Y zsBDkF2~bQJSZC`^^TJ?aS!rmK-24PMl_}$)#?ZuIqR)^5>!--f@^@f}30#s)L>%K3 zM}g7k$!7!`sNp*$6G)4nR_TlqZqa=SU%^Y)C{YH}Eo+WIf837Lo*hcT$h~pR(tDaN9*Q0{jOb&nFlj{AsIKw+_ypLvj^TFkNq^5Pk z%7P0DAKOzP(xU4*oC&l@JZG4VVganCyonO0Lg^SBDe|D5hj!*B^?LMv=_}^9W5eoH zUZzL;q z<_QQkUplP6E%_|zo8CKrRnLrn?p;@tm@R0DC`QTPnEh~se8NPnSetaZGqc< zMiKbctNBnT(io)pOl_2vHFU*5y&`sR&IC+6HYvptE=p=6<^7Ej0M<&q4k2^8=j^j61#h^Spnu&U|e?e6)A5aGsxCHu3O#cZL3+ z)B7L&)&EZE;28V&*!`X82aAoFVmk&1vIlPX8z7%K;>`$Mr-O<`9jQ;ou4`vDYd~CO zoj-&xIEltRH)<8+3xL42HwFU(14kW@Y4D+$LcN;C2Q4xBb{+W#93S~eXelu!s--Im z#7H_E6*iyE9~BF|FxEvB7+fsg`j0;F(=4dzYiqu_9X4rfFK<5aqj$QnfPHz=x>00F zc{fDXdXwZ)0XST4;X|YhK1qn#u>CKP#`PyJL>-nr=l{6pDhOuBA6JBmE2ac_ z<4-VwV2LTIV}2^PvAnWC@lp9imYyLS{=Fk-N~X9tRq2UY20*X9Npx1Fa{s+8xBm)g ziK;7PCf{1*zGnt{rh#@llw|TG23|=uYA(^v=hG<>!g4v^XoV#0W_?1tkX-C?Y(86$ zd-p|ncSugs{&7zLxlA~Tm({Sf<%8El;tJ=#c8391q4!FHk2gvbpwQ0)UOc#)=gq6? zecfUlG1!#V)1|do0eJ$j`o&1vcI7v@=2GuU#sCA?j)GLlo(ZR=k>(muM`cQ4z_++k zOejNaY>G7Y*ewVZbvOpuvyG(XKI@4A{9>-w)jbHRCR}t3iN<_ z5$s5LjJ%W%Um!|hj%JGAfW$Qjx0UV?ULsE=UYISltcXQ9M^82H6AU{CCP>|8SQo>c zE;DYV*k4_t+vmwIp3F=#A#nW;gnGda*JO{gc?01bJ<_K>9|5!aeZnN`m+RNDfh6eJ zT*EK#h_1Hh{KjkmFYbbS0@g^S#N=;#Z&!q*Hus_ZH!~ z&u6sEIg>z{;k!cYgjjs7t0Gcd8QTAhBbZNP><_)oTU^eB5|3WrnBxzVJYjkqm8azO zS4UROo0r$v6vlq@z3#i$hnUEDOr$Mg&@&sC5~RtWOYWw@Q>c5OZ8ce;pdsL`tQFnb zULfkF5~4>d-QZev^H+2A@*H709jfIUug?^HKU0);T2ZoW3EzDB+l3mn?oZhHaeYtq zr?i@o3`hKE9SN!Gwr|I*!hg#t|667GzvX%j+NK$rX~OW{*qO~gjb_Wpg0Ni^R5-H& zm0=j6l8zQK13J}J6tA5eokY{3EI!?J=+%|ccof|RxrX3{Q8tv0#hf$yUbRaP76}!&7Z`sN&EdSq;%`|MN{T)EdUQ};ddxywN?vN zSl1oAmL2|%cvTky<;a@B=3`55p{0&%5x0q6xWvuVrIwNmjni})@_tDBQ5bi>kA<;1 zICj7^_W;vVD*4S{TrGe_%^t9(6(=;(sMXNSj#73Iz3@es;OH_%vGfhQqg~`Fn|}hP z{GLQL=SJ(ks~~pra})qyTfHXU{*;o(h3KG2>*B;E65Qn9F##fUM$7zeJn7ZaQNu=n zzcV-;U>^llYM9-Ekt#eqym8k8A;MQ-HL}G#r%6=p&Oh*DfhY4{ec~$i_@-Y{`z1oUvcvL zqJH(r+X9ExaHe^t_cH+Ox13&kf7Y!;C6)LnyqqHSFGq6!-CAk@6PgofiC5Xy&1~M) zG?!`Sd{*VbRLQb-!>ubGKq|Tpue~i^`0Yx#IXTzjNDb)OVSc>!wRw+*GDL1gqb4aj zGfrUQRJVJWA}(O;CIc(@bl|C(Wg_&lXY1`G`1uJO9NydJ2*nm;(g%!+hZ^ZJFp{Z5Im;<_3=)H>*xBEfz1 z6PBFVa5P8GwL=-#!ONMUWL$$HWKSL08lfwnud*c!3vv8|!M$6&yPHhadFnS;G<0fl z_F(4;F4K4fi;2%BrIhlZ@=_n)Xn7QEBB;t^;`UMHM~l#P(G;{{h;8vU$O z`9GiG7YUh7XuL4ZN06CjD%p6u90Ng_dd_e*w0tjG)GLE>G)NVIxhR|6+}YWA zHy2*1964l05Vg4TcKB7ToE2EQ<$myPmE2L@%LmoX3QZ!GnO6`2htTRtrBY|Gi1>u0 zEw~lVHwHktE%2gMJAH@WA6_GCd4pG&bsB9_i%AU`gOlJn6nFYxqbFu~T1VR(Yu^y8 zuyF>Q;Z*d#vRql;4iQqTw~xGFxY=Pq8j}X^?6yIf<|xswKNrnZrjv?!E?m>pMUloT z;DfV(bvKp2Sl}T)r^E1`zYAW}EC8{MYo30|B%#}^X$v@xf6U&54wJ+Tt!Z&6ykEf` zZ()zB7lM_-cayt&C;v3MCoo2xgEm3^qC+7ywvdUA1n$a1tP-D3;%tZvl=j?e>4c_= zbpv^zeXTs{*~?ngt=5r132hyYqi0{rp*N>MybV9;_fxqZpOH^j+qpW7^xkn(QKuH; zOU{`AwoD-5kyKjlQv+fNb*FRIq&O{aSgqh!`w@w!sl`5R{$d&q5ULQ zoGcJOD^NFy#~{k&NT!JaP?>h2&?I|;HUEtGWd}tF=HbhHj@Hfc_s>+bP=M&>8j-^pDMsyRe(JIVmZf={mgmwR{!kO^$SOb?~r;R zC%t01MWQzsL|zGkQat0wzHK$|_W#yyKWx@%br{zU@lT?WKi&@^1V=&n%|6w0Fc?(} z<|;6xjZ&HwX#(=c>S{8*L2pAKPLIimp4S&Qj|yDfV9_LnwWVwZVdcgdP(X7W$)2`_+CS`eGl2ti$!IMx+ckPL{Elm(7$&B&4+IDwP3PY ztk@y{NlPO7o0v7)4Nfk4+JrK&)^S`KXaP-ge}a086AZZd=j4FOX+_S_AIwTX&>|b~ z?X4Sa^Lcn&_d*I919T_l7AKkXYQ(52#{n4J*(8KwR|;RWa{wg-0AXw4N3rahph{Z3 zP42o9t9-FTT(v13v!O*g@~TGBXiaou0`NiStlLrd!DQD@el8R7wZRSt;(IzTO-zy&%S&E>+71_*(0xlX-9)K zA5>SWQe(UfTqIxb7PiVH4KLp@!*HDSky?JFU%#85tL0ryU|1{Xw2o1?t?j;`7b;b7 z#r|9gF&t+-j0@HyzZIwxk)b2%CIVDPsV*Zv)4*)Y4g)J@Mn7fY<6yN6Mgf3UKBY@7hPGJeGw^&*95 zN0KQy8kB5zkBq5aZoz6DRhO^moyKuwAF9mu+qc+?sVSf2M`QYC`)ju-+e+yIo2Z^S~x{lPJ0Tk458ndez3`+27#&*CN zA7Zp-KTxb6mXm3<^8^M=EBe@mc0c@eh~v8HJaUrqt(oI`PaAVYVL)wW1%}5oCY#?t zK|mDhPd%*LiLK$Q6XT|`FBwB>XQM)NucI*SGuf*hMLrQy$>!DR?QaQ&D? zQ9SsAN1WyrLI5zRwXlK5Pn-Z zzGIGu`&r@~-O_M6?;Q_&-aG2ma_UzAF9y1eF6Dgd()qkbPqOrjt*mG(Qgq~bi6V{F zYaH9XeOeRK<LnxNRhzt5`*=Y1n)&sPCQuUku(J3A|AR$uG2r;7^TFb-tQTTe{7 zmuyYU|NSgM*MX+w=tEE%YwV0{MQX_-8*`IO6f}8Vr&aI`I|}K;9>3b%Y4pHF>nuZL z*S>oQyi))(pMngDo5*#gj4WA|%(uur`TX^P4%MB;7DjztM!6zEZ{m^yTzyE%wMhz~A8a2WW#;(+ z@XK`!odShP8^Ti~O~PP+CZR`h)}^)d;hm=L7e6Nls1@zHXFiMWoj9oqdc%4w=Acu5 zBWeLXvz1zHp-|Yq08FDpHX98f;6Ej%iXDY?0cyzFzX#%Iry+(Qr? zFU>_%l+>#AwDnQym&`9Kl{WMeK$fD`Pkc$h6#Pl9hW~UBEY3)+Na}%vu{X3fkA23wK(wVMc zs6@iIdh@O4PXQ$~HJh9CC>*S*+yW7Z3Sis^1@MLMOUjhtLv%Rsh~TK2<^Pnh8(Hrvq z>b(jju*YKeJV+;qiDZ;KIB-*FA(0*{j5g5V6Q48q zI03kH)Bu|M%M){9EtbG={f%t3Ni>r%;KR5S5QgfdDET z`lNNqv5-{alm1!L{3@$4udho=CQ?=_w+x4A&Glek6B{NPK4LxKjM@zRblxd#aT%z* zDEBiRPjSGFnVG~|xQ-BJg7g#$*Ngba$x~ot%`n5BhcA}xuJBBEzG>4WDdGXTIL_ed zK-d?Jomm8sYv|NF1z)6bjoCM7{zb!g3v2%b+;K3w$DnA&-TC-j&+PgEbk6E@b?-RE z0SM(4y_~|wjtVb*o^N?ozStd}dnrqS(Yqc88X4VMTGK%gK>p8IsUN|D-sXF_lRajv zhjU!wct2Tl=7Gm$7g(15RcZx#yIy@BvD?@KKWCvV7SthCL-ESIir0myX1x~~E4{)= zTxs00k%H9j^gfqbO}_qlCKAc`{g~CkxV}@rc^~cOcZPRhsqY;v^s4hgc1co1z8j`w z-N?1a(2@eeb!Iq_VtV$r5$RXNAEga(e*)?FvVIi#M%5VM0f}8sc$ThRZ?%=Jy&*C5 zghcp1JnWr7i~XM<&E(|kr+_+eHM=F%Z<_-pXlpjKk1Vry_!xufZTWgxLUuJAGT5c;Q491?+KtCU{xCC8^VK= z6Qjj8?R$wMN9TpkGJK0U7~kA!l_l9~c52S!Y^ zN6081fIutdzhok^^T5I3XA-=H)=k2SX|8aRderuZEf z%&!2RXZK)5tooZkN~p(8vjg!rFAQ$Qr=k1jL+yX)_a(VYB2e21AEFz}eMX8N+aou8 z;=qoYsky>~Hd}{7?%Ok}s}!kgR_=EyNMAZG=`!#@7V!4%Ex8++2n$kHRUzz_SL}L|Tn3UNR zXg@U>{I^N+s!#b1koPRGGs1p{&(865Mdo}s>AEM=7!ccg2WP5BC`k~*d2oRe4#4md z&+(JfI%w0SDOl~TX-cb@@HEyQv?)%YJahU?zK$w_yH}P&T9;tD^wl@i!f%`IlgJ_Z zas7nBd4*qJSG8|O8B@xQXB0r_LH7j6_E@n~>bki2%&q6QWFarB;2?e?+O9vOG!%X= z8&hTiFbWw6&(FZ4E}|M!f+(|t{vwiTYy4mR?w3#DuGHi4sT_*FLL=4 zd0N*19 z>?)ik(sl=nLr{GiXZ+yo@P!E4i$8#UWquAY%S4|3F zd~_uJoDO!o?aao8Yi&&4`AD3r?hYe^*(y>_(0o46cTr>3FllK?1$gmtHGSkkT<6z* zUOqm?Rzmc@Yta?V=xwblBHwK%vr+0o9&+k-Br}G|az+Uji*fNA(NtA&d3)N$u??pG zS=u7SR?^HB|HfB;st3_H3ddeh`)X?Y;AH>E^IjJX|q!tyx6Xd2S{S_tbw>eWA|oOz-&D|`o|ndrRdovkhZR= z>lEv~m+|&3FQI1;CaDzO>o5t$kE=gB3@@+4(+5E02UvowTY4$?H^(B^Dbn|* zl=%Fq+wH_H8!#FgTm||CSxy6JtkjelLYy1O8V!cMjp{jIIQ#6kpa*EnKw#_}O}DNt zS@fcv5u3qffsofRs4>#!f4=}r+2z-&c=KIbe`y4 zy@&$(vSGVLW?C`?ICp`|8YL=f6>#+e_z{6rv{P=%1l>zp0 za&nGpXU+BV(U!r$6$l8m$O!&j~Z0xToi@NK((|){t&j#4Bx3p~fIj zy7$7@4}VE5a_DoiXzNM;e0Jk|fU>kvq>FAaYS{XucP%_;oM#j9379>f<6+o&2*lzL zy_P2>e}rs1%qF4Ra62~w^Zi!?v-J5(r4kyTo4I2ofe#H)bN$GO+dD0s``YeEUT8OL zRxqJoD!;K7q({ktm%&^YdOFyA78rpW5lDv>08$G2g)RRQ>pbX8mhb8l#%hg?jyuds zE!gveNCa5Dv{`p&%)JX*fUL$5VqwB10zY1^kR^wFbc*}C#?GyQ0IZKhn&Rd5Jge`vz=9^`!|qGIkt~$uOW3xc{D^S$SD3L_ zud}K`>g;5!Go9nd1*Gd7><`j^PR5yLYqQ(4ynjo9Z&f%ils~om(x$}@(h9WUJ&NVjg2b^&c+ny?!Hf1(Z6(}dcE%}xZI+UpKfSZDCQGv5=?G6!KaHllOjYna z5eLqJ;$@>T2PgxMx3ij*b2;ubUb31H){I7KEJteWHSe}=oy_|U^xncaelmyA)MiE7 z^C}?6d3KE}9-tZ5vzfX6$kG!f@7VR4-w6#Eq_XK-ioRfp;hE-gFYXEzfdLU)%s+_= zL*uLJ`3GU(o?=`1X5tYGfZL$r672nSm^`^|{W&X;D8jy|+?AolZqMu}_I40W5Sm1j zS?invb|DvdcfSAo_uN|KrrJb)fV(wy{JBcD0o60?sY(05>)urFdtUEeB~N(`lW+h;O&A9|Szuv!w;&b^TsFYt zF)Hw5mQYcYEqJ>B7_Oq@zVWrE=?L#m4|Wz<%C|SbJ)bcFw8`=FSEw=-gTqeEvLIe6 z`kD9V#fqhjGty2vzbHV&0Fgfs6rsX@0{eJQWBCVrF=UhaK|*M9^_>9dJIEIp7L((@ zgGF}mrjB-?{0f9h@tk-jUaR;KMG8A5KMwmd&dBc!zyKJ1zs{cwOy8HrCUyB)Y{cXs z6yzoe(y`3fcX+b6K-m3_NB;LFVMy5!iNfi3o5^*;r`#m7jcV@}F>Zd@21P`4%*@Cq z;OP9ikaQyZfHj<8E^EESA6QW*V+`S-dKBUMQA{)BAzS~?II|g5SGHencp4|uv&%l) zPhb2HHLw>mNVnPk6xrqzQ;7eATu@4x;9Yy~tk5r=Q@Fh=o_%gHKuZ7f{M)s6=iU4N z=yu;>g)NddS7{7?%K{QxqqXFdqkZZc%f!T9+~j4#OIi?WB#f(b(fZT~U(9Y+HC7n6 z46}>pLA%#M<3DZEsM9XH0HT#5NmlF4J2funk3}6ilZULBZLzzg`$aQB#jKu;QP0U^ z-2#+wAt_b|{eCf-Rqzey)dNm_6SGBbzl@`;`=9l?S)?(i#M?hy6br4red>ZYxiV<6 zg2Bw=rA&xE84d5~5dLDJc6wSSk}=cD<=}shODZ6CjV4gu7Jw}70p!3l0{r#hsEL1U zcbxpOIN>_{n2Jj(%syEc+ZRV7sf{x-JL!>0URZsFjOUIwFy$|K0lOBq1OY@SEQwC? z{Tpj$UFL!n@PpNK3V?|f7}6}K8nY7on{6-3fS@i;;*fuEFPC5Tuj!?_#*c=d=qlgn4K=HIUSmnEedV>GMdk@ z3;)pZ3gH^MEC|bLF?;n<->gPQK<*Ey`wQa&d0jWn#ij4 zj_|(LdwHH?yGDa4`Maoe;gSBGiQj93!}^_68k!*h5Izcj#0DWuEt^G6fM_AAq$2+k zm_XMBL`~XWsaxx86y7%x{5!9J&FTqwkC{byLr3v8+)A{Yz3wAj*(b1OP$cnp(F2DK19;4`XK?RrT7fZAw~NT3T8f z>Fx$WkQR`V?oLT5Dal2L2uevVLg{Yl2I=lv@IAcmc+c7AjPH*#WbC~egU!IjdVbHG z_q^|GGLIt;=mLW=S_rrXoC`%=K7mEL@zoXjiN-Evo-AaO&PN#U05%kde5 z-+fQ>quXozMD}=qSC|@j3=p_Ar|WENzQ|lm;1kav?EiTjWh(yl4|K)=HsvC-f+{PE z!zm>eNO#{l^}$dn@_v_@F2+NBBw}2TN2JuqQ^W;@Pw-pqXO-=Vbh2?lW2ifCz%%7> z@M+ILVMsfx00iNX<@6u}!hGzS#nS!dL)+Xm3lGfZxNs}r-UZo5AlCq!aGQg6Tp7F-xg6+i ze(Koc*3JTX6&SS?^KZe$3i31zv68_SF(bQ_h$B6hK$r&tQr}N7KHgGQM6a1T9cg0> zWe{rz<{jX7PaAZAk)fxEM)Gp>4e5(@d{2_66aop{aXDwKF^Vj}!ebxRYm)fe*U$6C zKDY=7!m{L71)D==*u4@Q*n*aiD~9t&m-l9>@o<0uWHH1*jpH5Tllb|NRLP2wpt6Wc z`>VW$jhpA`jj&DUb9=V3qvPVCL$l2-=%9wtW6ru&e!^@(dI9~BNi5wyh8eTZR7CIQB$KfSKIz6oyyGA?kXpMTp~#>@Tta!iVKrsM!-MGBb48i)Rmv;Y76A^mTr*#GCik|VFCK8i0| z@ZeM#wnOi;Q21W!p1n^8mbx8t)1@bya4~9mpDQ%Fz|^|TF^nFNXfD=EK{VFam;5^l zUxofP?%s-mI(l9GCuj{da*ianM>sCv(B!<4<9;S97-i3}UbCzr%~bXqttenqtbO6F z>1_?AruXqKrtrBEm~rRbF20>UBvdS}mj=EJlWK(z8$8?iDRitpVB0N!B+~e}W}IX|Q*kpeanZw0JKT;0;Z>x*s^i^fO%PK)HGd?;k(|aD;|0kyG`xK7t=iP5 z_hn^Pz}4~Y{RvWyouE+X{a&P0oV!ypV4C$2R#b)3>Sk%%2X-9M@v0QRG04@N-6BC8 z0d-??oj+2?do>X-UxAmmWFxP**b>ao&+j;16GC2;{|lxK(si1ib28~lQ$Pah~md^OP2{ zi=9tnc(`ao^M|*t+!ptiq7P75as8_mr|t7FL$mtwl;yCzyiyG&IlvId^qDL`c#wK5 znk@GY=V6QGfupo$4{!qwD$_fkGldm4u0kn%+@sd7fXnxEXRCZx z1Fce)c9A&?;vRT(v5*(1^C>-kJ5#q~clcCRT27_3rli;@z}u`7Q;6jwaZ?>Ld;y6JV~E{VAi2Zig;fG3AW zSg0=X7li$&4ykwn7+rfd?D?1bWl9bI+b5H)uxFqdN#^rM)#zDf@Q17qjM|nDjqpoR zKHzmy`hwPpIb#V{Hxb5Q&1!^bSbS6okW2jZ=UWmt0xD*Xj-P!+*&lVJ9$=T1#NG`1 zW@DNQr{zH*sNJC`QDEgmt+e~Xo!O00hp&ORwXHb2xnp~6JX83U4DiR)=VSXcY0ClNX%}FRN-(uRa zJZA6rdGhOy4xIMdv>em7w>O`3;oSz8^|z^w6bKuO*c9cMU_j6<+`lhMc=hr>j)6y@ z#ea=W9t-9F-KMTk#e%5IogPV2oAM@BXk}WKeBK;do+??Z5%pO!qTx^S#^;ad7g-Y5 zr#_Ch!vpbPlkFueiwBMu&pLAjEy*4jw1E?yy1%<%0j*hqVCBsxq!`k4Yts$n(L|ES zeq0%A(#J>b7SX*Q&|pCbvF}7D02_GREM4^wel7{lT7!%_AxNuYb_16x-cUqRd)AcC z6Aj{(MmALf6RKJ#>^H{ESYV{hk6w8qMI7m>c5VkE$zTNF;gdMDfoB4Zyhpvu2gO=!?=}2K&lmK8vKA(Y>&rr?G#!wmR>7K;ACIOK5}}AS&{Qr5!161 z>PPmBa%PVA{tNJ3mihWX(H-|izjo&l>jRvAw8``$9`L0cv-)1y*72#S?LCB6-{*6y z8EVrGTN<>UNqh4FE?H8Ne~r*8{|hSX;xW`Bxy#*0#U|=8*A%{<&hxjh7@M@dqum zXo$fU$mSpM1S6z6N*JMYkm2?caDUsBrSM8z{47s8gqMAhOK z#DF`a&;h5lwT~q4Hb`!2Dvr3i5Q*@lGMGPa@uJ?_C$zAJrjAg%-t&gP_3REmQ%s=0 z$1zBmE7Dr=O@P5)uz|7hhuN0kO-hUORbn7_;c znK;6b=wwR6qrpwg*1(Xyto#;go}dkxaT{RoqsM7bn>6ntIdLV@AdRx(sj-WkI7NtnI1V zrJ*3P=-gaW0)oTfRLF8g>AVEi)Phm8W+j4^9c7J*ABH_k z@8^4a{g`8kT6zbNhNfpO0Z#^1^WZ9qu+2;fBHwT108# z;LO#Y1!7B#e8qdU%ee4s;AyTSR z#0xm#atn!Dx

      g`l`*RfUkgEn1grU`g(T{#D{`5Ir)O&>=y?M*szN)gB#km#=QUx z7hw3WWOI#t4%`tFEYpZ);f$?c0nY_YumH?jK3X-OWKuLP&KBIYAaOmqXixxB^zD=n zy!=QgXd;uZMy&CE?l7vfEB{r$HL%Bqa6hu>SdHvZJc{Ml-2(5q@X^zG+f)(FQ@4Po zV6719D-ZIh;DstN3<%vgu>)D^F&82VyG-MyT;FR3pbbX$u7R9Oj`v<5%V34P@&Ir_ zjJ|D>01hV|cC)D78#C*2;Bc$HZVu=Nm1@YvEV_lL+{OH9fu*Y1voK&&uDHI5d+T?s zpV~{17O&vUz<%+^CG0yrkj*92oDS+i6l*ZgaB!=$|y__jv(qt zsWq4Def})Z{o|fytMtv)6YB`dK>HUQuStNVwpJhLjU7(L1Lo59WaU4xoT33IB0lNZ zsTHIk_evN9E~f6|;F64QMNQ@yTy`)MThA|hvb;~^FZ3^OPv)r}KesA>3C#1xBTV-3 z>7tKTP12HWO#lrB>ztho!5YT)<>eeCX`B$+$a*7GSUerG40*K>@ivyCR#}AEA6{P# z+?d+oQk?_G{UNTYL$>1?P%t+z3_D$PU`io+v5rfRzrSuba#>pLj67Tn zt>K+mqY&@n)N982p+pcSt>L<~Zm!ls5g~$o_&3G+Zt-x%AGRw!H+QHnT}^30d--Fz z19$jUZR%Nibi>Pgt1Eso_jGxtX*=3DUorHZMiouIOY=(g`IoW>dRPJJ&;Nc&++GYB z0|cDc-j~DB4YsNXO)x_J?>``s_MbohMF9Wzf2?rec60ihM=>68a3iM9w1d7ut$+j1 zy6snc`96-%LC~Vww6!~*CNeb`)V;lK=I$TmiO~Yfwl0?~7z*QwGdfu@L4K_5rQO-! zhWHBOML4d%TX>GH90@%jt`No zgnt;0Kl!ErpQnHIr;UONWZBWg?R?#=A{pl!aE?EN0|738j+Su2cbb(zi{&|Jis5=> z6e_4@i7T+NoJnSAe0tB-V7Y4@KrwXmD3UPVtB=mS&CxWV<#lQFS-v&t31QS5bkUU-FhCn!0V@ z&ws#wJ-pCe|Mzf5a{TGpdt~!Z8nAW{7?2-^w98unQX2@MNuKo|p@u<>8l=tcLGT|~ z41zkO4`WV~f2?7uEMuy`ae|SyhYv8UURD)$;Vupl>Wf{we0kVvEq1!J6Q>P0)` zMUWZ}h&-DY039sgv*mLE$_n3o;4Ilvq4&9Yl?#l!2m!?AniO$YzuLg1lg&=uPC*DB zExcM`AVLgY`!?<8v=A{HUP@WW04PfzwZ_Kqsvf`TN$>J;z^<*=Wm zfdLzsFf;D`cEaq{y)8Q+iM}5@bUpp-N&&*Xxp5DqkLPn_e|%1k6(LC;2WWx2P=4Hks)^G}W^7soz zFFbc|ggak{);Y}oEjeZI+885Y%Mut;r&gQ7kXm?9U0LZzY>bLaehq$2xw}@a$7CTX z?D>;W1}@=Ap9r&`dQab!O5hwVmUcSbjj$IT{Hf;0bZWgdBz+hRklGYll4v-94!gp+ z$-&ceCK@HSHn?RdZylG*saB=-;N}OJswo@kH7fXIs~SdV)T7_4*k{(^37D$vrZ-sW zT|QZAZdKBM_CJo~KThiZJfB#!8X>??dt&gY5b;__3Mpx9N>$0eD{>Zbr^!w#^TyHx-has=0KLZ@r6~5AteTymbHU&j> zBsc&KBJte7DD&G7DDwU*15(JQaE-&RwO_1%EF!DKi<~1xu2`e>neAeFOf^O*ix~_} zS-ZLHa{TJUd{vR2)@<}WdIx5c^v%L-Blf>kQl*qGc)Yy=eq4rRQQ0l?I=qRm{mSD$&<5p zKSq~-*93Om@sjq}RieoDWO<=4;3jhC$~FG-`#@x24`;bb2e64tU&r)XBo5kKhFqZ>2jzoQ1!KnZB%YtqKVy&p0Mh^`Eg z@dG&5Y)0l$J-gh9BgA*!X%#c#<1Yu^BdaL;QMAMj63VM&%Yual$uyuPxRZUtEp+7A ziQoNG=g>VSMkQmQR|&MmBG-Ge^l^s7vP{qGUU$qb1}3I_ZrE=IzkuqK;s^ZFfP1ku zomvg;gdj_?;WLK^2V&m?9gRjOv6P<7`i?7rP}DZMg}>ji1LV2f(}7I|Wr{;e5r?GX zZy>W4l00N$jso==y}i4NzP5( zpm(4X@IokW1T?)EZeb=L3QCiqyp$<@U;_}oa4HWG-%>j+%DDSVyy|%=7yap(G_DHY zI}^L8nAd3;rz{2y0>jlQLq{M2HlP~EEv!zJR`DXoM~gnaDEDz+#=9(jiK|X_yoJV4 zf7s1hvnP2zUk0&~Qpe^n{$FQljh~jihMW3JdB?^NQ}tpuxUPa7SCW}4s;F5K@=dXq!&Krb}pG1jj26r<2}#5D7`HEx2edscn1J7#-p2!NyZW(8oe@G<_LK>>cR80Zur zHxAt4fUpnfSm`+8;8n(t5aT|4|D;LWR%JWGeHV!IU3O}K7Ih@SI+}uK3P@T&q~cki z`r5>rMUCW1bmE>>74~+qs^@eg4f_eN$atKZ}kPF&6_0%WI(ca zm7hMPUu39D!E}`v$V`*72;cwCA)TM(a>AXnJaP{i0dz`9$ntXs{X2`8v^onYM-p}_E2+W&y`7C*mj%NIbBjb)t093%CV$bZ{oI z$zH~BS&rJi+IAHrK*WzW~RBRXTl;Uyrl8A~8K}mK3ZZ z^vv8zmh9w|#-03A>Y05*uyVz(K_HUQ+us~8bv+tqb)Ogze49^+TQ_GVQtK=WpEk0o z^yiIU`jAc-uQr}QBR#wDPw>UlT|39wx@$}^lrK*1O#Gu&SR~4LlE#4BXiP*yMM~8S z@BezQJ+@U2c#Uj;4w6hJN-$hFgC*+@XHFclPw%u$u>}KH1=2Zly15y)%DaM#p+Lzg zx07pM2htDBfJPL-%M)age)Sg*^bP}UREjB=d6IGG;Z7mOOt{ygs_sWtWcp}_Qv~gF zE~|JY4X2OOX(5OE&q161PgpJ$(1t`ujEoDs|2{EYdI3nr>+6v%oP*nZZ5$n3FF{Jb z;-%(*7$tq!cR?esDE=eRehg6X!2JQdI{-WoiZEUPu2yPW-Vw^S`u^`NOSRa5X{!tq;G>OhwfkB%pH_tD%jU0KrMw})L+M)fL(2x4s zgffq)y|n`&92wAeeHOT;OHUO;ZB9_KA)T?k$ekJ!MZNe%445m{-`Uk$U7mOpM{o#6RjZ!QmOjE1aS%tcmsC6iK`gq;E?SH5 zOq3H&r2s5@U~H$dnnV@)-V)_E@)e}p7#DC7XGQ*nB7%y;x&YE+DHqfg8w2CmQ^n78 zz8VHR%L`mTvj#QOAOoaZfAe!={dt?7N5QyCF(Eo*ja$ z8%)iB^F!{lf%13QYInZhhY3@?E>hk$9McSTmQHMzYkFQp`JK*#sCTOo@QzdZGO3bf)e3;=!1MgM_-^Y`_+x(;r|9fGJgxjZ!YI z4K8zR#A<~1Tyewe0<97!7ynS5rN$v{aDlDQBn}KlbMwBUL1xERAnyhsT9EYSKyAly zaZNf>GNx(rBipwzhHkz(skevQoqXBk4Qm1DPZgts=FA&L3>!15SejrV4=Y%IK;$J* zbL!?qY+mBQBL;PEmhKX$gqLq4o3o$+LeEJaRV>G9YWKAsySUSo^3gE5=72sE&Avz% zTRJi{03@(>V-ub!|I?KB4~gb~OQ+Pddq0nC<~k%I(wN>^pkQ^nSpORm$QtYp$r%@} z@QL(`1Jfno98=x|3LYn(4|J3j72%A67e_sP(Qm_+u>5sigL4$9X{g8&LMUiY48fof z7~U*UuvG#W_nr+dj$5^K z5(pNWDTBmgw}aLV+l7C=;<|gq$wy))PMEhAkC4Jf$BR!Tn2=Sj?=@hlh-3*0CE`zQ zd$5-**n$B}9|>8O=GN{2Y#6j(U=u(AfDKRo$Sp}Ri`9q@Q|eY}@v*E$xA7_25i+dECGi8B7> zW%&9T)4+Q|AW4H?`2ki@ex)3}E#FtLt_{o~Hh!UAM`d@gVJfZNjbu`V+A~lcfeV#p zX+Nr^Yi^MW3n5yI0x+d5-o8!^rt)>n#+3;%VGR10$@TIDl4NT>z|{Gx8`7fI*kI)@ za7S(3M<>Y^F0S0%F)#USzq~(UZy9dA8Fx5wXuS|=xoz8>&os`{bHJ0SQeTx=3pm^q zNhIp$;9xTdWDiJNKHKj0hVjR8PEO?-(4WC>*$W;yySI?I6A>qJd=z+ygFpVI&=U3R zjKnCki{{cc22i!KzuP+&HAs=mEojQG{a6`oXT7V;hZ91l%=oQ@R7U#hLCGY6FF}B2 za4WrGp4)vidcnQy5#sUB0`NbBM6mqhe?mO?n>sijn*zIB<)^gz;%Wt0o%!3~5i=BQ zkK?WfnA<@MQA=N!?Z4x>rV~HX(3yUU@PvUyk(=_uz((_%(q07VJVK zpfqK~1srYE1wvrr1T%d@T829V5cj+biT!sc!8r>#-fM16iXg;eT~(Zw&_#cy{eT+=GXBiT-Al63%2@-C zKsR!uLV57NIN_Z6VG02T?yHnY5h9SmvfLw1_i{v*jjYrK%&VZHaifgl<`$|`VKFh2 zHit!cowK^Cy#dj`eTTi6hG03j_=74GKIV80rtel@V*F- z>WKZQUdy@qInCbBk|jSB4Cp(hkQo9F@d!v zi&sC-g?uD_!c*S3}AiD=yRFB;EYi$;?0IPmGwu%@`TeU(vK|?jL+x8i&41e@RF#^07)p zh8DvGOl+zv0))kDjia}iMm+B{`L6T#h?jbzajcLP$K7L6F#()|o?Y><)+7mx5dPt( z0lw6K1MI=f?|)rZ;R#^8#0;o29}fyRGy!K+fMB>N?G+da6zxjeL!m3TfvB@j0f8od zN}>)Qpk75_{^LAp5Xk#qZEQcKUw`CbN2Jk$A;dO-8m671|v zWZ+0-njw0?3HeSaQ5|H#P;uIB74|3bvIG+!_)``XmchaLhHW*E-yH&UXg%;wySZxg!>6O%ap&ei(k;>jv-*yES?TiUi)9- z#AsvCCU=5`4iVJ37O7xOSL!t`pa2;f6l%^=@j?Xf&MRu1!#CP^0XNcb6|HPOkY~tP z%hDBpK@~4lRH9jN9V!wqEKwS%^Ab0dLYDa>^`SSC#MNhksLD#tf7#fCmVoO!JjO?s z{i_cpNKGsxvL2?%Zz205{q@d(vdH*f?L7O}-E|1N&psY*IU(}hhq9k^3GvNL&latD zOKT_-G}{o<+}RGS@q^_WJSy!Rn93^c>8awk=f(_RF*X6^8-%$v)Jc;GzvR8`!nY9+dW8&M4Dob|xq>9#;bLIc{W0%Z- zbX@vE^73JLF#uU1VdE0AdFk|A&!S*x%oUT3lKLTq+8(Ju#Fxqx4Gqk^+do` zgISj5^>d=VnUfzCL0d;>W_~_%`mYJ$x3`5P@(E7rTE?%$Ih{<0U+nG0hfvG@2uUlK z&yRp^ZIjQeshPc3I@4w!X}D_S=@Z>G@=iSXQ^zqz0(OA@W*%0|-=l5kAjU#AXmCze z4G?Edp$aJiX|hdKWn}NS7?U2r<+ic0iCc%2^^uo^(!ybC z53hmk4L7gO$n>wi3wkq0Y3fUI?;~axO|)^2DKUU0n?nscM`UwVRRPQV?SWR)FCry* zgks`*<9=vlAt;W^{+>)%UB5u{v0ELv+1;F&vOUhxCz9qFg0` zgVcv@Qk{H2gju^G><7r#^PYSJP`RT%jbm7Qtf&EE6u#5 z;l%!;O63__(QkviDpFH!%I#DjUt`vNF9Z;ecmviz9M6 zaEoAM9|rYRf7>&1zU6w$qh}`w5SiB>#b^#2HIrk@0#Uz)in581mVh@mzf; zcS5QpTvA>n=|7)Qhu}z}{^uXzIs~4cgU|C!C>IpX{`Q4iEb@%E_34O@M>eWR)~Vsi zp*SZtFDI{D4yp}SAWUWF$g)*f!=m^ zm(CAA>M0*mJzdS$%w%~5fv~8vDFoB3m>Wr|F3rg!7 z2GTS7mL=!i=`N4RFp&sakdvg%NO^W*vS;=*u`P}0YrrM8Bj1m)<}1Ndv3rb5kIaDc z=V7}km5S8_S>8?`x|a54X|&C;94w!DY$7|+!RK6lJMIfuzA3*~+q?U7m?y-v5wPdr z0>%flRSa1z4`#ZL>BF`X%VQ&>ynt;tWHOxy5u(AYdCq(~^y3|}kY>VkbJJ&~`LHqg z7${gL>V3>_(Gop1ZBg$Qv+80jc($7dZI-?4n+t)#hgP!?WW!b`CTc!D@2}u+egd$h zPfWimk&Nh0p?eb{WxTgy77Ped3d#u` zU+Idtk33KB+}I2ZH=*TC?fBg({C>Wnma5sy1HH5Z+DZlFDC0aFuFq8xOPLRBZ3+p} zi%g;sjrNqouC|Mh?@u4dPg`LQqdyF#_S?~D%`8!Xaa;qc@?O^?w8<*n-R35bkv^K{ zj_MtUtM0<|1|({#{%8`)zjVXmzcDy9T6EMa#;G3bEBeR5(R6xs-!>HKX>#=BZ3s42 z{WaB}ck;*7$W4qn-%0L_YWp7Qes}Kz=hGRw)nFeg(2Y)Ic#8oWOU(Cyqb~z_5&37&6k}YU8xPp}j|XGvN~r8^fL%oWiXl+Z)K*GP%<0R<0K$G9 zu%R^uL7@sCR(jS&lK=v{ZVK31T^V8w)1<2R5DoZ0i#U@)xuU?S3pgJ$t5mIByk~2+ zIm|1z1!W3-weRaL(!;_4yP4Dmnl0qYIfje*$n1@ZDT*ftvrL(3GG1Ska8_x%Sy}tj zw{}@Wa7MHI> zQw&Mi_{_oDa46$)M@73(8lD3A5^k#Vrh{L{E*e-^&>R@Rr5 z7KIXIC@j`Dj9`#2F)q8LNs4zs6Y_Zby~Zx2P!u7M{P$h>_!;_t?!U*I(33R;-oz)4 z?u^sf>rCrLeK5;HfH;kuQD(vhzX2vk371ai8S^~&g2LVU%fvjcE5o@Xks0yWhZ?YH z+SQvY1@swj3&EB#8UC&1Nxn!w9fZ@4jtF1u@&+k9ZvauUsAY_yS(M8i8P|1Y$nN|$ zxN=Z7<_lx*&EjXdtqwO7&HsE*$hTc?D9P&_k#JTnqBDq7Q0{Kr(>-Ga_m(Pn`H@3@OB z0dg93cUD-ND29zh#@!2sQfiw_qUSV2dsVCioKAp%J-&@2gFCZ#k8)&PBy+!B&0pQ` zI@H|t?i}yn0J&u5?=}XzDqfpEih~Da`m*xGJad-j148iZpl$qouVrO__1TZ?`~aA+ zL|v#ZW4~g+=G*ohwe_dsI$(E0Bd?)ZInZ!fC&e|_;6@ITYz6b-MjS_|Bl9%ol;F0c z$Ve0hDPJ_ZBADNk92}4?usCS=UMMk+-=zM<8~48TIV;bWs(#4@Ze1g}jMz0)C`cmT zGb)gCPuI(id`nChqABf=i{AaYnyx{pJB4yHf{S$34 zfpB|1&LbzmQiyk~c28$t9u8~0FW;J*!)9NXVbV%?*K$q2Qm7P?eGP~oIo5)RQfV^$_u51y4*4L?PON4}PtGVdX!(OkwBZ67fM~U8Kg*2j4|EEZO zjUD>WlJ&o8RB%QqXq~q3&t@47yP35{HN$sht<3dO!FtOvv~WKfhpV1q>J!7@4Ym$W z?;nA0zUH{@=C*|Y*nQ8HrjOm7p=Hq!W|-FPaKJHLugJ4!R`6Grl#?Xk*9)ry928OQ z%1>;&MOUb4YnJlt**UN-k8LAg!wbvXN)=h^eUFwnC^Ys>8m-GZ0kA)|?|DEO(85eU z_rB+FlWG$?tXtyS!@m&9`SnN+NgF+9Oq}KGf7Z*Im9tWCypvHcWOGRYN6JtS-3@`g z0(9;-Wj*MQabT22t3!ol(9}g(d8l&7g94$KC=Rj^di!@~wEfEyICrlvXRA(NEztt_ zFl6x9nUOnLJeXwOKP?w0NYoRQytvZba#tk$l*+Hj1hz99bHf-H)!Nwx!Fw?_USSP9 zU!W&gs&>{pKeAOb3?lu5dAZAfVr5XPAde;)z&+5N0Jvi=mKJlvMy z-4MlSMce^DaRZH2ud7{aQH(BQ90kG13@y29vH2P`nn9jFb{?@va%T_0`%qtgA;4nH zIvYa+<%)yl$Hioip6u&^Zi;FK6Zy-rT~8lQ51Jd<*j zhps1|hW(sOrS22>+Z^oivAjV;ZSg8#8OB}875=6y7Y?9=pw+S;R;H!n%!IEHxv~o|2GlZ=Nv7B$XBHAlz9j^JJ102_64T~d39rRw{~;q zNgGRD=an`$<$h`&T~kVnF39@t1bFJpbEA0C49@B0xni2q%&{_}psS*<`1 z7Xdu4&^A^rEJL`jpnP(Ep-yU2r@+4@a$2kCLA z??*$397z#t4=12S@&*u?r-m%h8~H(c_Va~qmr}?N%EkpQnLmFHSoO->31-FNZ1BSX zZT*^@-Wr$E;|l<`fZa?jnrvV!r8d?oC8Vw#fS;Faki*e}kmIyaf2y9sQ^lofUDfXs zsQn5(_Md}Bktx$(LiyL0F1aC~Cn-GK2sEZF(H)EQ_?~^#X!B1Q>YPGL_em1FBnSJ4c;B3sr4hQjQE=$3M3GjVz?;6?(K2S}TBoNhv#p1qz=2A|eu;2#JpmmLX!CyprC@Tsd@jcB&Km9SJee2ktUNvVz; zy*SHE$hd2vMFQLqcz6V3K}}419$mjjtji2YipuO<$J>~-)EgzHZSb**>EL)ip+Z&i zIK(|(6EmS%`A!3UCPCzw0OGP#>~XEqG|6UBa+BLic}oGBWDWzUw50OI6)4-Y(tf0A zqeBJb-hkah@fG8r;YKb|1)pjM+-6rFqdX+!%vo$iEiGRK+yvw~UUY_^y!*+B zzWsA96>*l4hy!{HE?`Cxf5+6jZ0776Mhj7k5p{t#ga37!4VmQ9AJb?b)|#j_2GG z_`7-tIZu;E{mdj$kEzWFKmLZBa$_P`C(p)NJ*E?RL2XaL$kMr=LnKS&Nsq>?k%N~Y zEwzA~9?ya9yZsaa***gz8;&tG>2*DbF`)H{b$Gaz+?yX$Pruh#qz2TLZlw!SAAAG-Tls#{cdhwp>M z0z8u4_&P9X@}zMYa2P(2v*y9sk)Py=k8>ocvZ1RhJG3bwq|&|5cO+2n7<4;dQ&XW+ zXw#@`w-gc@2%$JeY^p<`As{LvcxbHe3Fy(9=6;T+LRoW;5(bSPhnJ>Dm|*?vOw8bSsC2rEW;3ylSRs? zYhq4K)Y5#~9!!#WnYR`VY8YLJ|0vd`ePQhp0`g{BG6S)_!DEXOtPPpi>uYJ*blfF{ zxUl0l_yN&?=3&CJn0;DZ*l4czDt$qY$zzpuCcoIa`TY3}-w>!K;{}|(UB7Q7$p;4l zH6>3X9JIl&UHTK<-oBrCuO=L$sh=0H#`SUc5WJ-;3XL6=Mr;<);ds&iZVR39vX+@X z6G?vId^^tlg(&puyU6ND`=dG5x$M3|pvL@!A=`Y;-LcLAT=?`Qon~8hoCM8sd2i=pGtt0brWBX+cPNv8ey+2h0|p96P69AMt!KFW6G($pasb*<3Gld_L9VS7bRT$Spd zI&XG|*Bur&LdiXZrWKTXU?RfDskV(Q+XCdDQTQi;-Z3wO?eS^#fBkqF^h50Ia)c*FnV$Q2Q{c>% z!p8z$1oDE^^@vpebBE@$7HX{Wk$qgOM#k|jwn6efGDv58a=Ia)7+8XC4FayaM`4jY z>vNbFDk%OggxGOiGYaA|NuKaV%8iRC<6$mPrSzI^Av>dW`b{RdgEhC(+w`(6(OiSQ z2P`Zy-Yfj>cJV;*cAq*X6WThpo{&4!O=Rq_IauZOkYFm?A=mbj)eiL8$1kp${^JF9 z&;lNB29(Z;zwwJT!u7tOkqyx*v54j`wy9qu<`Rp)2a@I4AxJ!7WIEu>Ztt@o80BLP zXM&B1^gegiV;J4CQ@_zTbI<9M6-7=iYgk;s&ni((KEMB_QD?C&O<%&JX!9*Q=>>^> zIo>VXc4$7nM^mmVWTH)Dj74q4cfVXV$Wv$W_x(?#z{MR(cRBbRiyu4?>LjqM7O2P= zNU&G_#h{wNH+D&2q}!{ZIs)mSXk{bqu5e{;WiGjFx*A7v2TKU3D2k5GHsyyYVauZC zHsO={OE1V>nF4O)dY_94C7;^8k9vHJOz{0{5>Q))X(mzEdtrQs%;$ejxwc=X;d{eP zew}8VcXRC^Jin0eBN6n)38-(<7-}3b2RV+(^z$nY&D8Q$mMc9c9M)>wsXkToyG(cP zNGt1naF0A|(?HJ9At^JaCqLsj{VP>tPp=^lZgJ$&6eb&>JwhlM(t)tIJr2 zUNaFgK63%LUSFYb=kcMk&sHa7ygZIwoI~Z*{pKbT-&5?A`)ZqKw){b`3wpRXx`=%i z*71uepa&a!)|XGS(EP2(ljvv!IeX+Ns~loOgRe2@jl4U-0Jq$nfQUvp$7>dPikQH|nZBTR$lGn@w?CLZLqD zzZ75jg6w+HvpT@$_a5{eS4iJ)824nYr#nftbD3FwHNS!unGjiwWb#PVDU4X-JiR4O>&1L> z>cNMq=VKKc`6f+9ZS&%9szv(tHkgT<0Yw++c2H=`;o%JQhOPaaW%`eR;;SG0!nu)ASEF=0qKVCX797lS?9+$-m`wKv0Q^8FrVkS?yGJMoS(%& z+CZ`hkCqTk;Ax}8=JCS;C7=(LUu`UF_LV1g#^?#XOYI}H2g|_UlP~#Rn-Mkp#TRbg zj_9UVet#N|4hlT>@@S7woKw5^)uvfFoE!0~13X~9y-_U&=A%_`M& z%H>3=WdZR_IkYt9@9R#e^Hn~p|rGD zQ;Te+mXM;wg*NGGN<^E@|BbI})*CrI@k}TwoiH-a!;<&Tz4wMZVEk3$vmCk4>PAIc zxmx$QblA!{b#k7AONRHo`R_5_N=u_;lK18YNo^xvW_o!?khr>|^3m5sZv>u3>hY=` z*y-Ov?RM1BRQ#Y!Fg*Mw&Vlti@^9$OQb2&R=Wu7Zgf3_g%jqMBzEu?Z!x=Xo_*n9^ zKL4FLgOi?E>2UjRY+JZt*w2B5J}q(&1-WU`d?SWi`me3GUl*$|;%z?sEsZIZQ*Dxc zSpGV3rn~pe_s)p-$+dO8)*f2_*T-imkgBg{32vv><>x$WcpX$YtG&u_e+SkK&~rXO7uYkh$t!qjb= zg}4LEXwMYjzsL@!AjgeWXEjY%K7*9Iu6x>s*N2Km_Az}-p=<6fbaqRIiNS02p}L)H zwjoW_og4WkJRgKyt_mi<|J#3JDOx2tcF7@>>RFXD-t;`e?jReZ2g z=Y>X}(w-<99K|wc^}KaLo1S8SKj(8azhSjU3h;%280f%|!|o@H-ZD6Yol`P6J~=r) zEA)A!;W64S-p6gULv_bL-wBZ|inlhj+pGx~R)ul1^$fAXYZo<~BzPp$hr*r;DITmp z<&~!jEBbL;$||h`e?W;yIK^-deQri_MZlyqII1)1nh4wy3wVqoXvlDSZxtWJWhTR3 zw#|8866Ap#(?+TJ9MOzM$6HROVNHqsUpEg<+jysTiisR`p0;w=@NgK!Zv$3)JtQqp}ApLW@_9_BPLN6~bmrqiP56`5GKqpP`#HoNAn?-=tz{4I*NKN-12< z?c2Nd;RrJ7JelSzCYAi!72hbqGy(kcr2{GLgR9jOQX7+qx4C~O+^YAK%Vg6es53Ef z04@Jo(x=B0dXp!@FdvHli;0su)E+O#yk$Ca%!$bz>;Eh5T4-O-1SZIamGM{Ut;c8RMFeI7r=$d$`IP z5Pi)>#!_7W2xv6S2Z^-YJqvJ1k40eFeuzY5MI0_J@zZ#u4UVc26SZ>L63=5^`K%Ie zQrK%%|9#&o<+H2L`&0&xRqa&sedpTYbgJw4$PYzt37%p-_xxDb-91jR=8v1SfBrT~ z@YnZId#!bx{$0x9I?t=<%BH9`Le|eO0%IcN+ zdEmiou?(w<3R~Ig5P$V!>UH*6_W$L9`EQnHHRGR;W?=i1vCZG>mg3O{w@o-9zsDD$ zFv?XXZOzFKYn4CEg}#oQ6Jt=58UqkKVdjWk{uE%IIoTGMv`o}TwkY8(R-ZkKFa7mB2J^w! z-g-*t8Ha!|>qZ^hhhN+^ME#k0+(VoZfkkVFsr?&PDIen)QxxQj<~?@Ln)E{WZw!EW zQ^Mhu1Xs%VOVl=eDHa%yB3ou<4}{O?fVqk0{Kl#YdiLCTWraOW9k=YkP%_*DK!4)J zkW0+{;Dd3}?7g3EQHCPz%9-v}WqL?d)*-upAG=_z#c%Cb0*IXq;8VP$Va~(sV4G_B z_O-;gVP;+L{g#E`%s{O|Soq!3*C+Ceg3rkpRa%bn*o*+S$)wsgW%snSAb&7wBF}4` z%CI;rkz;m*gppU1$8C;vrFH(x%(+N2NRr8;wu=$rMYA3sMm?;>kjw8V{G=&YCN=v4 z5{nJ8?GW>idP`=$7xgGR&Ikp|80NeSNbO1&e4|uD3*Paj;k4F7{S2>pp{bk28s{VU z#*4vDXVW%27-6I5(TLqnAjA^?Fy-2J1!v9W(&yece?L%4EH{A6mg zd|&6{LmP|NyT=8khcRC9N330jLE0ICF*>?uN8zr4Q7U0B6~GKNo}fKQ(tA4<}BXIY>jiw z^%QmBor`!jorqCS=J3jI7n++lZw}po zQ@nGimn0U5DU?qWpox&@7Fmhp46d&hM7<uek znUWG5e>NORSvS?+-R*vsp%Txlsegn2&M#M*InYQS1p1C1+7|YcHMev4d#%mA0yhe-h z9rjFX9H0K}RmtOA`|!9^cb2_Me{dLwUC>1$$B^OHuwzP3@BYfYltM>Wp$MnS4(I*N z=Y8@LKb($&>et+B>lE*YZxp0>jy7&+{g zRC|E@{fqb-%km0q!4dtJnKO}%zWbgQ5j|zEBjyZRrz2stu46z#4Yy2#kU%kWOFQQ_ z1GcKyyZZPG^!h?;xW&S^^BV5r?qK1J77utHoFF=xqs%_wK%KSw&vnD?O%M zRaAB<%Z`|LRlWaA$|R=rNiUe=FzJ)qKlafVe538@dLqY`n!eYk2!NAwvbKQ(>@H+O zo;!j#RYivV>@k98-o9nQEBP_DO2pC;ryjlTiIYL5oMqR)*0a^dPv7xcyxw!q`GyJ- zHLPDRHnti0jNe-$W%3ST9k=4*viWXoGrZF6M zFtca>8XVQfy)!pz`)c^?H*w+9=0t5H;I*6ADV_Ji+Ii8wG`dFp(7(t-x$ig)ls{Z- z*x&hdx;w-4z{{T2sTfPm-mM2DEEsnUZO*8C_6mK^Hl%*qgFITgY50eQtfmut)c)fR z3@hLw$a31V^wv8Wxc1h+o_F0&^xFi8&p((&&RksXOra04V$#Q8=G?N^A*%U2H7N^M zsyu8jQ5^eI;~~hw;>)iTVBPs|0w_E3au&^)5WgL~(05bg2mdGOFi-BTd*s*aA`$bO zQ`E=X)5XpFxq~aiW(SYv|0W>FuXmU!M5&C!M7mvr^n3nZf?ZN1o-STKMqcm*kNKNK z6?YV(mm1z3#`ta(mOxoq?6)9S~)jof8ea?B3JjA$G z%m1SEO)T#4tZA)-mNy+Q7R7I<{hw?|Z;ZJD^M zg=Xd<`zFXeD>(c4cy0^$Kftph_p1r@*0sW@U!L!OHL|GS{eQEwUcE!H3vwg^0T*hL zIc=?rX01r=_i2?VsatA|l2p!Si|3fx2(=c29c<64pj3I|e%ADL4bG6Fwb<@ID>u*_ z)U!##vy{NOVkaPh-jYFzR|ohCVPJBTY~?F5xVp;YnSkPXr>b$hg*`{3_{A#N9{ZL} z%(l>4c`_PZgU-VsN5tyKllI+RNfL?o$%{-n;eBV1((U$AhNVrBpHpUI^vk?K&1gI^ z?f12E8JP!@w1JDk$+`D6#o_BQMqkfdfQlDC3N!}7BN_m=mAs1EUAGw|v z68ASShjB1^rRA*=hqMkp=#Fro80q}<;jXY(=zh-VvYzwx;`6=BAHWHigt9zrUeXjk zN*ObMoCKy-Bq)o;rOHdEg|Vp@UB=Y42`yZ+>9WhXY6_B0LuUK27`!Zgx~Z);+`jd^ zo^>KyF;oFpX45g{y*FM!O(kt&;@!CZbF#h7GcLgD!}W*9`Ci;2@BivJ`~rn8y=G^z9MGM8d*mrZoQbo zn~)RXcc!n|>7KZ#e(2T7|IGyH!q;peV{NlDgGJDuW!~_RQlX$O^=G>IvDyAES@bmy z-lM9V+j@$mN3B0G^r^lux88zdntAVv$<>I)Mz^So@|c(1oe@lTYQ|%$76k|Fr&UOg zJd3(UpHXJ#p@M3#$9P#AlG)$<=nEy?#zfSGzMP9Rb#plXHT~fISCM1cuU1!`nR%6x zXZn5|rkqkuE z_aqrc3T`25h*TBlLpnF-rEm3`#PEk}KXu*}Z!$6TpG+iO)^ke+rywvj9W)+qwj(qk zKXS~dFluY^et_w#KB|X3Mo&a~t-|_}NHS~;d+Zu2*%Xriegemn`K?YN|CsX<#R8_U z9p(vs=BqCT9x(Ot6l3}Ll8|Dca6uxj=#^EVG%qB>;nG^b2QaxH>vX@lb z<1Pm$m#DoqCTI5)f3}A<<$T_x`)-B()!r|*Rd6|32|0F8S#Oja$zJ%ci=I99wu6RGC!~W)$sLq1hTI9?td(8F&NiqJi(-RB=N74BhL^=xZX-rK6VLCHw-2Vd`?Ts)_2N?(OX|WFWy@DcIsAQ0?L) zx|on1d}P)7lKBCiguKj51G&KV^tX818$BnI`qj5FVnQz%>E1b?)=l2JVYg&4=|Sdj z^3r*LljuR}Ox=ZttYm28Ky{)}R`ro~{bpRWjv+6Xc=X>Q!|j>zhYf?{vr7|eANDa? zR;Sy?iN4*PEig=O)M)JD=ugeH%xkyIZ<|F{ElvGUZb(a+4N0LMiV}Ui_5tJdDoJr3 zb_?IcfmVM1lpzPyG3L(v&RdIjX?W6(IQqt`+{PkznV)00mK?{pIXb2N$nXZ-!=z zMPKfY-TMU?sSJetK&-#<_;Ql}b6wkhTv;TFa9@zX2R3l`sGUU zjZe2~eDHD5!aPX9WNI@87FD@kR=G!;==(vRjd1B>+QDa5bx?gWI~`Nm$((2ME6DlWfBHQw=T074dE6{+c(_4H3+@djSJ(3H zybfwX#hnu`1+TrUV9nhf>TIuaBV+QdAM^=~9fF{WJySE1@$LN_!}s^i3Xq14iUXG5 z1C;flDdnRQKD?h2W1H$R)33!We8KRn_~Q1ulU}CX?BgzuQ%f>t8nEs85b zbY=vo)?SefG@i3hZwM6pVY*Dc3=D6h#b8eFBQ3w`-t*QAvEh7&&n-`Q*ZS>@Ibi@7 z3{$#^ z(zQCD?)@FV)i`soGcluTb#}6Uu;D7|Fd89ZAhU5;Q@caybm~19{+GnzU~`I`_s!aY zRpYXoq~2Uhw&By$a6?cb3Mni*vB&ZQ_!zaQxC;OS>g2 zG+ek-E*O8PZknvQ{hh7giePOk->~#KLgx<~lj>ASP=#$t$dK6Z=ApZ6NeHjisBLw~ zwYnSsGzI;~?fO3%EcmyUDX^DE35uyMfjPnKy$AEsa8LZeI?|Tl)}8=tt}&bD5B|Gf z8F&@H{An}mkNx$}vFczS;JwaQdT+SxBZLVps`qdwr7x)HR*b@R4)EPDEy zK=^!mckk8#YY_d{MfTZ}2$Ko2n(gH)l^QMVqjEpqujsmjoL4wuxv}-QAD!twcY6C| z=FYMcC(m_MBEznxjF$JwXX^J5S!nH8Ah*(MwSG;62jnsqws+87@1Hc{c~=k#tshbG zqO1I}@O(Xi6c)m^$7cTi#!p<-HV*#UM^PZd*Fbu&^9b&Dk3y9)<;=G3j*w4?l%PF= zSl2~Mp3TP{`{D-4&C^0>!9xCuKS7qo|HgZ}&&(<%O^%37tjgMzdxmg;70-CN4OA+C z0fvi~oe0YTt!OE!Gh4L$qKv#D&Ybo@g?m7s`KPo^K>x+2vg1Sy0bX4emw~RV>e9e# z%+d%Co#q$&EM76kRTpm;*Jg|kCK^>&H1uDVcqX`U`5Qa+ftspbEn)n^mIivqr3XTXY=H;9!uODqg3$Dwm;F>Mer8Igl|0_RC_P{ z0bm>GW~}{F^SLRwJx`>siupN@U_PBM37NjHXm} ze3XJ{*EY6)=%q+dO=}E<$VfccK2lwMVou5HrS|;WgOtJ0j}ybu>EP-)|5W{rtGJuI z$|n&KQ!jD_J!k7<%)Hgx@Oeo3xyBm<*$=?-3T&z@QJUen7C(U-lej?aZF9q`oaH<{gN~ys}l%#oHSl_5Impo z-QcYu*$eI%kE~L43N3SzLhhUL-ryV`9g9VKWSib3j@ejqGs*vP61YKZy-uJ||L=mS zJX=b(-K_HQXdldbz>emzqy0s5V?>Bw`lo@8iP3(jytSJ*sHB**7&U4xO)R^M>G8qH zxATSQCr6`}Thr6LrGgM^&E-Z6viC*{A0ws|VZPdC1o8jX?BR)pNmW=~xe5xO%jA72 ziyd>#!{c|a0(4W_J4m277WR^lS*U7)w0aGv%9;RIfNTXvtH6IKr^us4y|w4IJR6m) z>dU|TKgnM|&j6zZP2cukU9cy-C~?G!mDx(ylsPt}Y5UCVAu71O_jZ;)0P z^^9L(W1$>uG=m}+-1Xhos`j82euRvt1fk#4*2KY5KaugOIj9n^xA%rPGO(ost_KWV zX-BuXBh1m5ZH2I53{5v*?jw$ZmRPH+Jzn@o1?mi%KRn;!796G@3FW5c5bT zHo^Hb;Yftt0$!UDn-Zb{wXNlEVHhs7=A8WMKQl&G zk&v>zw^z4Y)BqGXEE{w|ZKJ3UB7;t5j?95TtWCL#cNT<$#t^>c$QS6Z8~WNxzrP!s z4sSHUZ^`AbK{ex1B*rZXq4x+h%|Q8wVvY2N2>IwbNi`YWc)@LbD~v{j)57;j>H+Rx zubQ*^I!S}-69>`X-4Ur{5hwnx`edQCDW`7^X7ce5PhKF`<)hQ1$>tKCn!jGbaNucu zAlPkDa8-Z#$I)E6G;dJgrr~yki?FBd0e6wf-;^ey2E%&mB%_?IH;(>U&3JL&jPKb8 zCG^}hC6vivU0P@LicXm=i=nQn$4H{UEMp!(etg$$DmZakQBUb!S*1v~9n|hsjP}I* z>->UqYv)dF%#yBPckLg7dmchNzm}T_a>CgC>vnc}2S{_;d^j#;)c+2E{L@nV&+|#k zNU;y5%e$9|RmPCr-^Fa{Nk8#`WykIKIMCz?)irh_gL4-@ z1j53)+oodgX2x2qt(pg!UN#eBR;i+#V8TZ>H?j7l<6uz}ABdatS4eZqsu*X#2Ime) z|LE{6bVa9saU*O8USzkZUJ-?v9j_8Cy2q*zGZBU-LCAE?Q0@c5Nm%fyyJm9h;b&dY z{-gSg{se3A;e+LKaXE&$*Pz-39s+a~rp=q}H)@rE)reJp`iDZRftBSOI`_`)9(TWM zeltZx_LTe;t)1f!0%&~px_z5z;2x>t=D4{&FL?dMdsU++i$IxRSdh|%&(irWxC&Yz z^)E;uu>p1)c-6?pGm$k3sm4XjcLAxoc?rkl?V{q%zn;VW!ZFZrND&8E)u_D*Xk0M$ z`Q*kViE`sTNOlLG;pA5N<+!}mbO|B=_RXL(9<*WQ#?eEBbMbZOI^nNIm2GEfo$mUTA|dsD2sr^y|d7%PcX z1%EUyLBU0vG}u-k<)XTNOmQOlYsvF1T!a8{?g^bqM`AwkDAP^LHGUZasS`sBF(gX) zw|B%}N*&+;0Sk!%5?tZZtyx}KR8 z;%wWAEgP9w&r8%#PbP6@x?{GxMCZy*Mvc#8o*b4C7gB?U`QwR^uOR`hT9Y{}x66$=moI zGQ+QVz$)4o3#y>vIA~X2Gx0#n_;AYxB=e^Z4isViO+~=WBpu!NA~vISW3+rjvXNI6 z1rJ3t$uYEC@Oo8dt5y%gbjO)n-(kC1g5$D-m~)3Amc5EU@FZSv9|1Jy`7}w&PVu9& z$%qVXLhd&lbNrchN4OZtqXVx)dZIM4->WDzQ%TWs1(#SR`yIJ_iuGZP*PGOt;Rwgl zaci-nEfk0lVW87>+GFBz8479VyvdO18GjxYBGoM7dc0BcF?|#i`*fTDNL78Y*V1~6 znT^DSc8Vw!B1ekDFiZZeo`p}NhHoLGk3<=czUNfrDI3@jcRfP%^>BX<`7ECFSSD40_xn{vC60Qsk7jj=*;0R}~7;2uwcQT*<8(j+pa#derAL7}^?Cz1F$M z>GPPlzYSQA0uc5?d@o?j%G((pOzVj6pb-p-I!8a9!kzp~8DV|F83c73fySZkSoASz zzg*OknmQJ_LLP&=-cbjBexdfB_QD6*)cP`X8IbA~hN1?!moH>bJC4Qko*o8Wpo9GT zW%`r^5$xA^-e|fXaIrYM){S0JLk|vMK#^YS*nj#@mkp;fW*<2I>%dVIpEE3D@aUh* zho4T03Prws)m@g5mL@xl{9-%MVDjq)Nm{!3#ce%f%ErfO35z#@Zd&YP7Any9A->q^?bbx8U`}|g~e2f&`V2Pkh zx98W!;7O4_R2TEt=OB0b=bFbVr(6CpQD_z z?8@jzIFR4A`C)&!H%a9cTR6zMF6gZbWxxg3*_kHUXUvMWTKh;s&fk)?CasiM@_$OY zr>9KnGSO)_t}r-^Yn9qfdA%;*wxpY%Rc6J>x85wYhHi-WW6J>%JkP3k zCduGHuU)5_t9cCBx7u~^w)vj@Y-lv5I&}Ul5GC3IZI|0|XS%5k{j00@-@hy^E8{*= zlp2=rWj8j#_5}jQ6zYF$4WgOvELVWoFx44))dyFDLT0jRqzOxXr=9GzUXIfraNin# zl+>eH_rC#$4`?{Kerh_mQ*!edbO@gKe1F>=UtD6pjdS!|OG0e(N0#0!rXg@%pR*&Ina23kpm4GBw&?vuBAs_4TxXE=2f~{#X+#cBf_+~Q-;YM*ONB{VA_M88rDl`xI4B=XE8Ko4jQZQ^ znbNDW$Mn?cu>#m3!Dv-_*J1l=m*x3VyJulTxtl?6d9d z`>R#kF`@D<#L=I6m`?s~pzP<}a|6=7R0Gln=dP!2`EJkpfJXT@w?g+H6#2i1PCA*d z|FWh{If4b5d05~pPvN(o+t7atm+5lF!5JHD^l_TUmj4Zv5DBfT4Gn3AWZ-PcH2-DK zN|*x#1=$fH+_2Sklx1qc=tQ`f*HSR#$qcf~6a28dE{D8}%Or){ocX@zUnbC(=B+-@ z^{{5y>ryNkL&3+TbiP{IA+*B)pT!uNhxr~x#D;>rJ3Bks)RZ;X=2I#08p~yguYrgs zQ^^@uZn((uFCF@8tHC_Br*X*0X%s9sqR_dvE)2CZJ=+ECJOgVP4#5vltFX?D&WsO8 z%b1F1_^w$ZgxGb+kbB?B4_erJ;UG%dy#~V)a38Iy+G16-LWh>sE|&o@$WWHG_o=(? zha}WQBP$bNdyqzf=0+E^~$fhz`5Cn%|kCsfV=g?-QP z937&d76T4ggl3Y8>k49})flG=tayiv;H_Oy5%xbj;lE2^FF$94{Q3Juo~t7~SUtDZ zl4Qm#pa?`R+E-rad7wvp`h+)pT3!yaVs70Sz1^K_voDPre+i)c*OKj)Pplq)_+_|$ zg&Mr^0QyBTX2bE_m44%nLzPh3@upYe?Be6?yfnj=ymR)}^0bqdD+l;pWvq)!OQozg zJ%ko>C-4f6jF~6sURe<#*IF_nc&~i-g|Ky1RoIX+>J4shQjeW23}N;5gyovepRGfW z?`lxYQR50g0Ocl#MQ`#_>77;+(RK9ke-QXvh4xkC4iQ}U^F1(Cg>^sG=GKzdhrTZi-?-cI`(Ts1`Jy@GBo=EyG&C+YVWO~&6JgkTd zJGV6UE~y`@uSY6vrE|l~LZ|pm{oz9`&-WIN?{^A>th0kr6#LavMiBF>_rc)AwoJS>jt%^JrOuM!{IM4g=YHPiT1C?Xm{ zbWp?z56@e256X>7f=$32w;;B;@rmf9Xfl!mPl|sTmeL}iy{6NM#8hU9$*)?~ zq)2MNMZ4!Yd1H+v3@MN}V!NVC`=s$|#B^L0*<>{uGdHC8^aSW|?IH;SV-CMb*5-oQ z^9H8w0J2BI0bwSPIre*mOfv3vqiCS|8ccHKn%^zffj4E$S!&n~x+*5P zq@QutcQC*jFj=tF!I~zq@JA+tz2dh(dxtQGvFKo{nm^>st_mCTu&SI=a`X^+&8 z@^oFu(xwbhN3&_lanPiE+#+PrXFO=x`7-Si1XAC!zUakMjJIv?RH1`MR>Y(z@L|qb z^Tc%(Lz5jdfBCUBf-eU$qh6{;6DRD3#pnv~f|=#A3C^Ma)+EKd5c>JPq%Z^x=zZt9 zwM%2emu8-#r(P=&HRl!=zTd+_vfqc7Zrfc%u7>E#3jW6IYTYvHnOi&}fFM)hPQv(I zt2ekH{12EL#p8=C2%?bCQODf-t%zL-B_hwG%&o`-|J$W`5n4m^JkX8*?Aq@MW(9u# z#UQYx&w%9~tXj{EPvQDh_lh!XZ{zxav?T*Yr)8Re`>1n8)+sqFKScgae{|Nw2f29TYg4?yd!?V#X zkF;YeY8IWQFRTk?p%F2^51s+2?Be9yxxI^pEm}=0BcM3j*kj_yM8ziJh#*SLGo(<)(EHoRmh!uHK= z1?)yjE3O^{>g6m@Ba`*Jj&dnz@(N%k1Gfaubi4D%z+OOhPyKv1B0bM;sKcoC{>$ir zR~66%YHH)81@#kmg0c#d0s`o^zYaFbG!f80k?L3RqW)11h&9}d|C{v> zLkU_kf|KdbTlzdYV)2-GK^{hn!4OR5q@rvr?KL>#-tQr-_2BJG=JXtCxl&XDW^Lq3pT_=&O1!}( z-Jbgj$^Mz_OclCc#4_7xJ3ptB&LtETY(1&bZb&Xr#}XD9wcegAX)SNYyEz-F8J!+u z)3UaM&)Z)*w|7{@!!%yPBb5{`5oJbk-`_uO5nnOnxy|;enQ2I|z0zXxxrms%>!ua_)VxK^_bwwj z{xVaQzAhKG6*=v0p{?6Aj-A>h`D&(B)kC>U2LHdh4F6kI`zJjp;eHi}VkF8a-jqv` zC&0Bw_a0|C*tew@YOYPe2xW?d=Vg^S$ENG%iDyhBK)l{w<=!`%%=Sz^x~bBt<5E++ zV4OyEeejhFl4VC#1|CyG(*#_rLcbvA(1(q6AH@jdcr{?Zfm1}k%fog#v z&jZYscZ%l=cG;v6idj?(+czYs+6~QZqcjB`xSA9m%E?m^IRM3kmy~O~5UfFIRH%cu z@<(GVNBfwMoqMu6cyx@$?+dz>htKRj+&Pyu5;t#aUlEyo7aYZANKyz7&oXi=dE#lD zANnRyJH)$c;A+lbB`V~OF!@#1vr!?+SuSR>g{Th!?it#S#^Ez0{0)!M5b)mgkE$S{ zh}}7^U{x=b<3gk3)sP|{_=jsaMsSPu52g5%<0!LzVc@Q!r#pASh15q~RVB_So{!a?^qEy2zqhA*yNltFwgj2id| zgeLlBo&%e!3=%8Xb5!4a3BOwb5A>t&mxVuH`@T@`)zz(Co*lK{8vIABEA-s#Cy!3{ z3aFA|{I3}~i7nK`l&@iXG^vD`4S+uGj zi=n-PP3EH@4EfX4^myN=!&`F+%2Nvm$^oL?qs##!s`wM`8IA43R`Ji4)q;gQT{kgQ z@g`2UQRaHRy}w^Erpv`*B)tonGkRv)tFWb>+d}H<=3Y7TJ9d;Qxn&aPk;}l^>*zWW zmVKm8RSN5je7y5L-G$n?wqYD2WyyQg$gqr|L-C@vLIwJtIPS_!gGjkMhE%I>)(rJt zeHex_LJi~GYTu)HU@Z_M(*HOl|7k({C%Gq*fuO@fZ_*<&;M_p&A}L}FsPyOY$Q zf32sUhUiFy0;my>ClwoNY%|Fu6;+xyX`GLkK^Z zYblJSo9kt`oy{8x#4!nlVwWQt!u~2rBn&Ko|5qAL-W^*t9u&axM#} z1uII>U@_$4mhAbyXj7N64DkzM=`YXNpkNa=z-Zmbx5|OvE~nC|6;b13(ZA-nn8K%y zDX>DI+~t!ymZf(@R$OkBoL2oPB>|aPGY>5Vl89!Ki#1MrFh7 zn`V{r3%FP(>zxG`hG6j^*#DJI`PA>Dkj*2QeA=z#n+!O=Iq0ev#Qxi8WlH5sps{2! zCI>JWBQo@=0-@!uj}C;7@^3_6(;wc7_AN3jx6EC^6$*2 z`tMaY?M^*i5_byjW(>)r*j1Fnb>sp?c~)^^y57fT6f@I-+zkb|6<+@>2V++ z>f}B>tX%Z;-gHIzSHmTj(ati9F&z7tN9O5Y2CozkJxWr^TydT+A$4H+^aq`CUF&K0 zXD2Gmn*2I%J;+g9$8x;&AIB6l1peE}2(aycPD~&KfCwRa0}r-5VUIf&kG{z6JEz(h z*enTOn;&%xyay`S75F<~z=1A2@w_0b%a=L=#dv{`&o#|p_Ivz6+-V4?11padM9@q6 z+Y!$PJ`(LegZ&R$IgCpTtxTWz$S>I{RxR?^dRcCN*uE}qeEutBTU9ce3up+`n@{dh zO)IK~aj%9riS9JGq=XzgtH}*m-`W>QH`kb{;#Jo!W9l>ds%cVU8+Tq|rzvvs01b+j zynnLqqX@^dRON5XN-pEC72y246A3ixX@-~K0-+`vV(P7fXwyQ zg*UGtq8>i9{ z+j&MklNP7}*AoWdK>@14REK~}p2ux9C=XA1N#xqBHny0JqP&`xUL%RZTwW%@!bbW@++vp2;4>p9DRlI=_UF+=kI(W< z%bI>$Gmu5%qS^dbf;civQe8e2!}pum@X9L;wyEr*W(Y7autWoj@G){iCHl}Ey|L;MjIUa`5 z8%cEtd0*}PP^-6ss4MAE7oLj-J&q+aZS4Kt=YN+3sdoQDtFR9{Sh6*Aq*jg_`qKW@ zgp#W~`UV-o1AI3G;$U1w*fJ;QJ1@X*1ybAE`9|@t=It^igzj82aZn3uSmKbf;WrAG zA(TP}Knb~d{SILi-<|qhoRysU7;4|Y{JX?4*B~IAH%wNG!rzppa=x}MP`a6s$3r$g zXWt*0q2a!22kiz!o+mGX9J`C>A@^+xYJxV^^I0Q>JxOws%dWZ)m1USG9APJ|5Wo_j z^Aw32EFcVWp?ty1%fKpe1jT*!BLt?acQcdq#c0t8?90mbgC+~9GrA+D z)GW|pvn^X=tq8H(Z5i(?H5agR9#o`d9ko@h=(@)AiXM+L<5)&ahl*WAY^Tjb5f< zL`vhKvX<9Q8W%7l=es%ZjU>8;nVv0)WjemF@^_qp*(dswNQEk4k$mU{4~T~eF|_HA+&IN#{So3gLI1P4MUhT1eUL(KkSc_R8)DES25Un?~H`%_{b@kXBGe89|Lb~h-dr32qwM&!z8w)niKC$!qvO~ zsm~++$IJ1LCnMrH;XI$y--)_(ViQOquu*NeXr&91!)TtfCbjW4f5wmB-=q3~2RfYg zEANDJh45sFeLvIt1dDH_VN)>_=oJbnf}H(zO4-QiM!~1od2>5FaRG}kByGGsWdQ^DI!oOa}m?7<}aqz}}o1F{+6wyoW>{Q=qa-6tMx{tw#(df z{P*29w+fcrA+iswP3GU9I~l)&)|W4!a#ee0@YpyI9Ze!pOOoD2;FZJN)MPrTr10BmI;-#*+ET!SDU^q>481`yWQEUT zY;ovXJR-D}<|{~`;bh?0dFYx%VDk%N^-MXdoMc3(x87T+y4xF>ZTb;Kq4I5wqQMea zvEOmq=lq8@@PyT}#E9d}5JBEjVU6K3#qG=`tq)#Tk~cbDb!zJq<8B~ZT09tW%k`pa zf5YW)~*?c)z$ajZ+omCxW5 zeplq^f{`bLiRBE1+*XoSUBnU2c?krL6D^)^L3O-&`=Rwc5iWX-%Mjux_aI0J9T$=Y zH52qk>X=T~o$VE;8JBooFMOJFIvEdSm3cgR?!U%~*Ht#bk69;V97AZ!?_-L1UN%l7 za%8Bwpyf*#E_TEEi7?$F?n&*Ot?jg|oN`!JT&nOGVj@yiRN9C5K^mV8pO~!Z3-V!4 zeR!MP>*JZ6ULP=I|6!HN^_j%+W}|2%7+DB=zkmu3CX$1_11OqoEA*0wf(&T;0rz!` z%x#Ue#Y=h za0=tT@Ygmx+vSYJm>(QCn8MNg5_am#Di}GPrPX8Y>rIX&_wC@VE!~8q<-57@e%hxA zyXfoXa|!zsGse)#`tWm=-raiV(0}n*o)DH{;uPb+k$m=<#82YNMCG6r1}lr7hR(Mh z;vnyY^octZ_FNx&-uWdQ!!8MNQYbqlr*rawkE$ zai-lt_x|mNvJAe?N+Kw01bjtO0Q7w6B zrq!8F!3!!fB1vvf;oA}Vd^GiPu-apby7&Qhidxn5g77<*`GZFalovW-Gi%|T;6vxB z@>~jEsXeOQJegki>h_EJe@KhAV$s*YuDpO(62b%UvEAh7o)TV;1&ny#)0GJ~RZGHW z%zuya4JbkBCU;W(1)oe(Zs*+G+z1;{UTq-Qx56b(7fC#emG1|&FXj7=ZJrq_4M1IC zEwirS0(Mri_scV)v`CX@*(9n^*JD`X7<9hpL|&wautUk4e-MPEAI>Oy%ry~5msC(6 zIJw^#pNrpYiqsV7jf%UCQle01Uq5_Wx;b0rD4$8jqn~(;HjoT62Av%W2ZFj97k#vl zvGKBw`S)&^7vDvD8r-6(^)j`F z_T)N-#S^poJ;DjEtz_b~6YiRr{!HZAtxZpQ|KulFC)B7eR!2*h)p(Crvo|1p*jS@@ zuqrrm6+fk!7L5Y)iXmh9$xg6EPRh!agGsLVb z8+f+R!)_e6WXo3!1>g!})~b)u%)HjG7G7+ml^xWJe!u^?z+;6;`+Vlilt>W2(z3j) z%v&A%EPP!jgEQnokNd5hh^Dvo^_D;(EA!#Mcy`%31ziSx#&M>3i|6FvJJQt!L+m?H zAqi&!c3-I4%~v#L+if}YNTg1#sDc;v{!-$8A;<6RL7W&)oFES`qg<9P4{-a-69YX# zh{obueQ=g!$jQSa`DSNY7nmj-`F`yiw#)Y%OwGD_ONgnF)DAn6VInd!qZ>E0)Uq1u zjxt6*r{9j{^~5#aMckhfTftD^Q%ibyUgdJ)MthJECNi@pP>Yph>n8BvEW9Ls5IIF< zufCb`)Ang7ML^U4n?j{Z=ZEbcmi9!iO8t4t5660HtsXKf!zLAoOCNr>#Md7)2Meqi z6gPyY3!c!vC-SFDPEHX+ zrSE01s>(goo3N2>`Pe@LI`vXsdzoLl-M}9!xiqxK3=4Nr@*jScO(uw5fu#b}c-lHT zd7}1FZhE46uv$BeIvUZ&+MAw-FPr}uG>FTsGIDc~8-Ms#p1Y@%jM6!sl4F~SGTl6< zD^s|X=A)KoA5;ZOY>MSEQQ1RsPR<>lUZ>@LFLeH}=40}o_fS3bQDY{$&h8TiYapiF zj&)#@##*oSJfCC9&Bwu}q5+RnZd2Ai0iOlvA@glnDl#dGh=NddXFVUgqeLIIaqpnit-vZxc8h;MD zf>p;c(quVeP$2d4HU+OD3#2|9#Z_s}>WoqM&YO$CkkV>c{TbJlm}kr7c{W)!*R_Y< z)lp!iX-3vK4;6CXz}&oG#*tJ3CcdQ3dZ2?-!XKTW^6+31v@R;=?##hGoT9%^wf$NK zogCfA(`qe$rnO$}D@BC)1LZZmvy8~hSl_> zV*%bdm=|K@Iu>$6gka}$tLn!518Pa=x7GhO*jrFg@LywQK-!sxq>T=c@&~Ta-N~*J0*(H6y%p*PrIXRmr(`hHeZr(#LdIZWDM6b>GY5x@v~y; z2Y;(i*`S@nA#cOA5!D=VNe}2#5(R_M`-XpGV=*7Dnq z2JL2sJ46YoTo&YPKs|W|3}NVzfn#toC_wkvIP7Lf-$KkmJnbgS1EAuv{Ob{aFC2Dw zqbQA8|D5&AZF6(AL4qFcVGoHnG)NLi72x`8b7e1u=t~ZKpFL%{ z!WEc)h`yverkOlU49dAX~+9>G`po|gdN z=!+wF@vrva!rEv(i=VjKH)r1TDD?m9^!+C5-1oaEGSg9gxgf15 z;84q{y<3d*or|gic=+_RQ*m?W9cJ4E{`HSGUH9$l_;mhaU7L+4(zB;|K3`RUimC{8 zn^SWW2G$?u%v?>BqUi!@LmQ_3W`@pL@?Us?^wht)p#f|7uQb)a<)+k98RJ0f;=-0g z&Oc$=#+|9Df$x^hkrW_6Szvj(%1<9fd*=J0L(cG{^7NB%e)`VrGD@4hW)ZIRs*jn#Vcy$sCyv4u}hKcfZeP-K}t2|z2d-7^G; zC*w72VLfn9&yEH2gh16F5NHnhbHM|gWH>JYG!68W^T466*vTu@<#?~R^RH1DP;Lm+ zh;M46{^X?Af>v9Dv!Yhj`63{c>>4#ue#s8>@YwM$E$9k_SwYGL1S>>mUSb=a^FKrL z?gHgWw{XTdaH3*Nv?zwLxTg3+nWdsrId~14f4$yXKuQF`FTbCAGe@V@@_co4L!$@miW z^E)rczfOirIU8%f1!~tnIguppR8?s2$m~kk$@w1{Y3|iejG#a({>{6cA&wDt#TsQA zaDzB3y#8@V+6tyTi1{S{upvWM)8;KR`%y+JSAwBPtVMwf34Ru#Mos ze>=gmWrLn|9n4@?83AqRzo^xuFJVfTpIF-ZmMiX)1FALj*@wCno@g~DIgrrpCYBX% zIhTdr0T#UN`TFYG*;<6b|yQTM+I zOWDOcv8{W&#d zxg~V{=myX-T718D;9nhTJOWKik-C}m)y`yZ)50xJfvnv}N!PUT<5e>stnv!C6W<6K zAbFMdh)J&n%%mdfZ(0LsfTH^<4?T?;gQc`aD1GH}1Hfq-+$00V8DbU{*NCBsr>TkB zwn=h>lO5o~I+}^hm}R^_aoUT1a|yc=iXa7H>(Y4OUf|cgb|Os$U*AkbEVU3&QIMzO z9Bd9k9E-~KHXZz=ies+uG6+GO>J}C6F&01zh zDxh+3RvVZFCJwy3*XOs(%-Xu6JHZONke_69E8A$PFi;Uj;Na2`QrG(f>0JP8v{SX_ z%BJ_3KGenYMEf)ktgjdIgF1wYXQ1sKkH?cw{_jBi@zsUd^_Ay%uP>JQ_Qfpj<%MTq zU$}bs&AkppP5)KG`ER~6VvWRCE-W2|C+Z7EDrq>JR-^?=Bz7qOeX;QIJNnsd_^t44 zka(MV8p-hO6?vnMFXO&-8dGIur4C!-nlWc8yLF2!P3Vd56e%Um6T))F$a|B%oh{+1 z96+g!e8EENK0_iC=pnOi>2tPE90=7{&V4z_6bB@*B|vfh_+PgAoAjk&J*%(m2a5;? zF?J62PZ}b&KMW*afqYoQg9T?Y?$>YdSHoFukx9db$&dk=sa)5L8V*_%X90&R__{G_ zalbHt35>jhX@fso6}%_<0EkQ2INqJ9dUIQ1^~lNywD|%MD71quJ%JR%ljW zDv;=v(OhAXx+cHzlgd1oQ}4^POZ9-nA27hM&pBrcD8tkAR(ZQ^yo_F_iYrhNnbCSt zdWm^@&IyP>pxoLh9&VZ`#ovo&>;EWq#h(TpZuKN|f?e*=?P1dhHZ!K6w*F{Dc_Z`lk~YO7UsmNG66Z-+$c0y;$c{v5J5=8W~RH>M=TT{_SwHIp=?`H}7LTzopm-|?B1x-Qv=QIXri!;Cy1CXsAP@+dDIn z{yv)ky4D#+*n&$``K93L-iOj(cfXMtv4!LopLmj%k3J#T-byw*&0x}admFvRj>aGO z-Aqg0>9FKltWsg{#?Q|LNWxUW5H~LQgTYJ&h2fe$yY=byAIa;2=^u45Hx|DCFVVsO z`t!f7+>^6>PqAYYk$HtEM>Do>Fdc#&3)t0Cp%zl!AXELi~0|y z)|vKF&W8=0K2JkZsj)qdC724Rn9>sEwFK4<`hQ3Ac~|LBl+Sds_Ro&wo;X4Y3wYy` zlt0sC$tT>&hVc{@Glm_1PHUnYRT*puNLcuTlMPV);m#q>|kNv7FNx;endj zq}Jv|wLZjh3aHXK?c3}9WGCRe+9vvr@t0Dx^okkYH(y>44+!ll4|LTga!6jb)yN3u zX7t~|jvTsdgkP8D+;b&rA(TkSk$@#G{~ek75iuUN9N|e_K7*~GfP6C))4APaI4tt* zrxuwyqEz2`Bhg{(h@;8Vs(wp*f@3P3yq$$00U{NVyH-_hp3NuK%mKEAi+jHaoqy2J z_4+|9FIWxtMVOP4Cg#f*J}^9EOE7McI7|p*WPp`t5Yl_MX?l{x(P{%xG6iZaYqNQj(2Co=Cl3D*jJ8epD#Rh3^bEQg`6L6(KW@@vUAtgP(^f_C3Ew>;3 z?A2-yK@@y$%HcwTwB5HcWVJe7coaNKB_#Raw}0Hh?7kXTe1yxY`_fegu_fjcyU~AV zr~lVi5$a2N$+o7F>JXf-L^HrVS_)=cGkdJw?4OiH8=F3L7Hlchu-O%LER9Kc{Deoe z{_WlV_fOht9B2>|E|->X_81kJUXrp-D?ajthH(=ty(do(oDmk(c$?7X!Mz`na+mcM zo1oe9uNSjc3YpCtB(C(h|UOHU{!;RoTkzoVA= zczU7-K3nY%>DREq&(N67ARrRL0L~W}D0xPEG|V3ChKX7d$rqWnyT_66RK$~b^!wM4 z?f1phOLTspI)4RB@+B8$1-eu}OgXEkENZ$CXeYkUoCOYSb>XWzwaqY^9Yvm42lHD8 zIF;O;EtremO<#1p#S*T;MYm1e#Z+tCMY5#Y+&e#+k8N&H(?)5Vd8$IHR4by-G-7qW z-7+0d-If@8D&#(7s&Dn}yIU7{!s5n@7i-s9(!vrrat*;W`$8Z|LXLPzMqX>yZLe3O zKUE9L@|lW3nHYXy182zh@iaflR3;G@Y+WI!dFzK}FMs1Qa~r8sF?R7wEkBg?P7kaC z*mYEWM++Hi1LcDEEZbdarSDNz#9`z4B43OmolA~|-rw?tQk3hOn{E8{oHYwJq+xJ7 zkR_MreufD2ZZ=vMc%_nflbHV|X!Jr2L(cX>X!x zsNQ{hTe`HwPJ5jS%5u_ovS_@a=ijG<|K7cW=>A2{b6;+l#j@jBH`5Ec0Ad9c6lntY zUORx3J(y&@(1<=uU0Lfh@A$P0(k0j>!fe4m`sKYt%YHAKZA3zA^_UJ!f#=~!{iOI1 z)~URrOc0xAE2`mryLG0{hQ}e90`D=UL`DYaBuADHNm-ep+rVOK?8 zuqOxXucV$|&@GOsQ2Ve06JA_kz3{}B(0;<_E#<@1+IZF~tax;V7$kwNQ<{AhIb1J` zgO$%jkl*6SPP;K2I|E3lh0aW;lfaH0`5okpo-lWD;fN*~U|VYmFu;R`kU7X+XOK zR+>K7r_83TOU!i%BZ8<$x=Mje-JJ7QRKpj1{*B`%;cuwI`7u>nYZ7}~g3*7tcpu76 zch|vLQsDJ@M>o?$J5Yuo5B0x1&wqdWju5;jpW9tyO@_Qy&9c>Saj_)?=S+irAg|aUWYM;VETHj)jSFG9 zZgRBVJ5e-rUT689DG`HyXP@frmlgNqzBqmqbtZ6grm58`@Z2`8JN!M{ue45HT#)&* zNdJX8%`*vallO1Z?{yHXk8pF4>V8HvJ3d>ja!&VndGL4INa(9p=VMSpNWyTgMfLy; zVRg{K^mw}`S%dO6mat$E?)RB}juUCtLaJM0vdiNgg?gXH{ur)Pn$yQns^ZHTp}4et zw)cTnU>5@Ydyo{(^nls(fr1t{fz_z2>D1BWOkhk8=JG}N?5@8-mjzq7c*m*v<%-Gm z5@rsTMvOzvcQl}`Ep@yQYeoBv$MZF+D+pYoQm3LZehEi?_?PhE&@QHM-Gi|NaQSmM*!1)>*vvDgA*vp&ya& zJe5pA_22y&x}iDloB)#Ee%yBGQ&?x~Z><+t0P@+OtJMuQGggO2lK6Y9c-$jpJ$}e-ufN0N+!zE zaUBcD!e}vehF}ytyI_AcvWh=uoGh{e>kU)esrNc?b#l(1OM>2_uCA`fu}uNTy8JM8}{%?Z0ort8jINcoC?p`a8|0R1~3HN_X=9JrmY`LGg}K*NXG^Fvd$!a zBLi=j&t~uZq8>kPX^kp2=EZY3OtE?P(j%nJZD-1%eQuWG)}b+ZlMlJB5Dz|sZ5Y`t za@pzGOoeKrw-y#M|3c*ZVmFBV--zS?@vUIEv0<+NAx+N4>j#>fzk!#6XXk^1bOxXj z2Wi7VSd%LR$9=hcUPrYsDbkSU=P$CFZw7G|keJw59)A8R246)@xN;n=G>`k{seRq( z50ffO?YkPdzAiXu$2>S6r2c6XnFDD$BTrLSU&3dW2E~naLs2*V<7E$<+9GqmRB)+R zy$PGXj8A~1|8r}?S{&J-!ZSl+YYUY@T| zuR~tPQdut|wjEK`O5uDFfNt61a`SnIMW`7A7pj*unkZ@;o?EH%-eE5US=FC_Vd)NU1w&-8$U;nXYo00 zB4213fMBl=me$?Yc588Q@kVH0LiPW|Q7=UIwX4cZ<*Q%4iIe=0@Ob?5R<_NaZ6sN+ z{o<%#*)5h}&GWNo)4#=yp2i9Y2iv_fymbVg-7!8Dm&@XnsgyU=wl5(I{UlHyd*3lH#?BCglscxCM$_}v1;wCU$A?LC zRYdr&_l2ihFS3KRe_l_u_wI}6yuvi5j7phT=W*O8lTzVHzh3(PePpD)l7w>2pupF> zW(D@~#D7jwadt1@+r0nqYfJrm9Up;8eC5P+1?DH!1hNHl@-XgdRqE|(Pwh}<*777G z;B$2AZh7iuA7);M0<-EdwLiko+4KSJ_!%;xIscP+2nOAKJF4&yLhf&V z`PT2_HIFo}*!zWSKBD1vOrGZEOrLr~?K+5Upf~_jD4u$gx9Z9XsK@v{)B$lyOp9^J3Zy2L6jXaVTj;`%%=W`V&;dMNhs)IbYn#FpQg#%7dD zeQ-qNTd$9Llg7P_uhT4ezquUOY*QG?fQ&IBavjOa?ISWAt3k$NPtB6 zNJ1pJ`|pU_YK-X5wn>* zHy*cJTzqn4QJsh4?OQKz^G~Fgj^O1h6qLbvE-i>JB*u zB13L9^2ej0mP=6p-c6mIO+m?KzJf7TH$mP}-`k|jQ+`iq98it1UjEz~o68c@yno)4 zheRQE;aCd zEz&?x{lmL&dM@s9bd~%ku)RFEO1lo}M+XX<`4b#cM2-B2L(L1PWyxzLmg3*5Q!VKg zFh4p)3uT-PUvlaqb|W^`IbW}SDhp@Ko=CxuAY)V6(Fc9)#74X!ep5iQxJK`x(EXt8 zB`%JKvJs8X8kzqO)c*cxnw%rEBOfE{>SPm*4Nns7cb<+}}+P ziwDmr0!=;GNeIUBoDVmwXZjc~%0jDk=V`{obKi|Ld@Q4p6{x91NajF7;K>8u8px^V ziZ^YMPE-gka}WGg;qi|5DfdnVWtq1BVS1HK0iFr0@vfj_p6sAwE`({hjk_4CLL4au zFK|r>eQE)*q556Re4x^FZ_N{{)=W{048U#=A&Of9?0xNc#R+ZpqmGR`Tk!mqGSxw- z3|?`nyry;jt-|qj7Df>l2%l60s&L2liK3Pfbmo$how%T*3t^;DE;B?4Pe*cioLrC-vfVY?g(btrl&TvHzm4p_E8u@I9c{ z>B#jsq{*mXlQ_JZStsd#Uf@CvSo+M1OF$MykwB(CT0lS(4X0^?TImE+UHD<$6sp{L z4R(dab-7RX7pSsBjZgzlB{h3u92bfY$jBu=E2+Y@bkyG~PxJJvfZ!t;KL`jg2-N&Y z(Ti}Zb@`2dqJhgG6eJ+bmhofA>KzkuZe#Yv{JhX`gJ*E>^*Ng7xL%5}0>grP)vlR9 zBgGiY==lt}U+1|+H8Rr3j5|QuR?%-wYOJnog>W@%wqbt6h4k}%&6Fg2@%Ids>rp#LB|F!pT1$>ISK&&g6FOUuy~OIpjKas9}e^XcB(q@<)B z@$zfoL}iPm@FdJ#kIA~xe2(*157FDNxdtANJ5;F=N~BLsxWRZ8TrY?f%cN~A(#HNw za7bJMzV6p%K|uV#v;c|RxyZ@oHJvMhHfes@3}enXyxK#PgIN?PIiYqhKh&r@yzkgd zP#l%{SX%RIe#i&nS|QlEq??h*)T;U=G??!VdqqXGWN#x>!r z1SwbeQPS)EpR4ni{H*`fJw9!Tw}6o0;(S-j@YUsFc79wIcu`w-#oQWZYS<2BA0g>W zbLJOfAO@VuEuFT$TdSp@r2`xZN5UOeZpLjUWo#fzJi|FV=BUcISk)P11$Gh{>#Ym3?1EP z$-NK5=C|v=2t2M7{yi?%lC?P$o^stDo^rl`3pJC_^xfti|j(p zwjfu$_l2<3p0W@`IbBYEVUtBGFEnW_mK@M>mP>8hTufywOSE3^LFiL)G8(Vty;dTe zPuKm6U^A^2u-{&XZ1;g)I!i;vc^P!1ojnfhY26{ozgXy(7?%p|TCJb*W^3QMqWe zR7M+6ZrBU?5FB4A9Aa$vL`0AkRWVNH*c@Zbkz*%1HrScT+Rn25SV2gcPF%)yfjG9e z0BYhFdUO~K23FTF&jxNytMYTUMkP=`0Tex?{`S47Et>ME_i%fbsP<;IWWMWsA|8-t z0rGwj|IL0Kvn#3_RDPdGvg_AWi?46rvr!Vq(hs>spjN+uESnhiLV)AjPagi~H{&4% zN{l@>+m2V+2j&EdL0m4t-LQy1`VRd?+GZ|62pIG=D}&Q1=cmPR;E$$~qVe!6(h-#;0174}PA*P?@1MO*R$XT)<`L z<^RAg3o%XWa2Oq|4DHXt73KJ{ekZEX`9ORL&)}BV9esQ$f=~aUZsS5DP5Qst-+%wA*2={tVSfe5CngpR zznRM%_gJj^D3awr zhA+uq;l_WKbiY&8d_H69C>ymq&}=*C($MjZR6 z^)scx6MEiwTBB3$^(_b&TLA9Z<@dhp!)WzIJqi~#{A{Q}h}A0eCY_a)O83<5$l3B=9j+`JLfQ}Om^wT=jY6#Cop5ezL7YMOOW#ZI8+-z zWQDo7{cYh_W+X000+TN~kC8cUFtzdbaAg()h=zu7x2K+MWKjeF$Cm>78aKP!%c9=v zLI7&NXF^ol5P|wOy`TFIq<>J3LB$-DOrIAf7tH$ag^;F%Sk)!oO-t4!9e=F6Qe&IZ z(0M^AC4bsgpw*APh&hwN@iZKGgnb(f%Tv&5IDUVQ6k`3hzyh+QT>bN7Y>Y}m*Z7Dg zMe=ejg$i~+9;_Bk4>&q2JQHzA`P0Hshztw{jMJfN0U(PCi>r6N^DtTxhXnco$CQQ_ z-33|?J_DCd&oq0U2dIokuWPg<3-aB9-lHAoYtxQ5O{R?=0i>}Up5$hyaQ}vO4n%@6 zYlCa_X#GlB1) zf#$Y9beBRDt!F%cbdr8Dqx-LpFLeP?&@=ZVV?lOgu$14f{po?pw9nt!FUpX)vFE^f zXAW2{hfB9y=;FEHy3NF0e*smb(_2)k|JkK(%nK71Xk;uT>YL3k^?Yu^_+#X>$jp4! zo=M)A>vG?tI9iFQMPc#li~To*1u>2IVSRmFsFh;->`kkf!NC))+vlPW##y8Z_dxb6-+znO@hwyYXVlaPo1dWYi%%Hf!TT<5t@WJq>?wS-ccg|H2023BR6Zgw zo!ZOXvwKF-vZr;Sm=O%SxCNGYn|@-koSvsCei;}OS4$Pg{h+gcDxigA2Z2m{k*}_^ zFSf9JK#<4u>ZFv((feVmwi1%y-PPpKu`N=4QLu!un{XOZ5=v|tviDknK2?n*Y(CQm z-LoslsCYzrCTTG@FD4k3o0~>aT%5DooymT6?;~VFX+8&4xpSyF2m&{7Cq>0KJLvm~ zyay96aA+G+Wi~jO+~s>op@3!n6?ajsI#$}UcF6{ zhl@u;4XTo~!NBypUHHZ$paJqX0;-Wg&*KvW+?mDj=f-l|TsRaULxK*2{eTEK7)Se1 zXQr)`b3wq)_9O@3)5 zfjj0Y=hJk-@Xw9cJcQSS*U5cD;cs3~IC=*;W;4AigewqxoowL*ujHNA*4R%36{t+9Lf=Bp1D#{ zSEro+YNFn%vG@~Y7EBAB)9D?LM*WqgNN+FIPg+#f;@*>6UHbx}uv`}nhH4C?2sW_Z&APOfwOHfR&VA@lxVYrLY87G?#qeaMk@VeEOmZq@YP zz2q0~O3Q+*4DOwP}{Pj5SOXrEj7rRt|Bb|$*j{_v3I=dNyc5LAZbaxDeq8_{k zMB$r#P(x_UHSZ{sKo!*H;rx4l&Nn60B4#?<9S|go-6>D9O*pmL5|93z>*+ig{XR$n znm7ncxMNc300H!}lrgFX799;(jY*cEo+Dj zP~T9olTQTlO9U<3j|rp>GfnF;YyX-@%1`ycFYr)8U{viRL?S4610)Eh6}|V}GClDN znm#zeUJ{VHy(Uwbdb}@vv=j362pv9EIMn2dQ}ClIr`%lZ_)c=*3grzyJ16!Shc-Y0 zaW#qjBy}~OIgnc8mRXX|TWI}$&|`;6R~9uf?1tCzu?@PYlZ^L{QXjWPxpEs6*<;}nepF@zrLr4rx2P^N;Lza{O9bBJgWu>20+59N)=qqiYZjf# zwSDTTr9;l3-=>m(&m{c&Oi&|x)3OlTNusxoIs=~z-Ue+|B^-JaQuc38hfk54GV_SX zCDKXnicjx7&6)WWZTL>ORjbReDGpx97}kA5=>1M0?Ei6-Yje$x5R*~>M0H_fjqPh? zo1^<%s^!FVrnIn2N>2>|K(e=ywL4uB7!}0A?0!c?CS-sG8@Cs z#jYIg-f%=gQ!=XX7v$ku9&Rwt9C*S63?h-*UD~&pxPtLNuicmv2KqqOj?!g(E=XIr z!g8BdU;7i862*q`EDqk0@GB=)dGE;L!O*VWAHf0hQ6VJ>|wr5aK7PDVm{( z(&r*5GNf3mz*;S0muZYNH=aCj+oygzy~iGv`;nHaV_d;XYrW0IHJlF2zuY{9ih=}~ zDHsRT=(+v~9*B|RJx@h5+oB%%_MQu$=?8=@KIXK*Y zsc^g8jLG&Nt$RHCAqH3-*}t#85HB1R7OM!R=NtTU`I5eK_L*Vre>OQ?T_C!1D|3ZM zK%lDpY-MSAM|}j$AOj@KTf^s3u;St<3rJyc6sDa0!se#p5wy^Kzj$KU zIKxCBXM*bb!TxS)TT*BFT=E7s-L`<_&UzJg?u)C9bb6SQDaefQiz7EOm58yy3lO zHFO?->~b-_+pEv-*!a|4fQ#q5x);tMOA!h~>W*(xb=U$0ZH^(YDv(CQUYtN(|2$X;RPVQbl0 zwZ401RPG$^?KF5E)5uArcn+_U8#KwYTHf+C1nCj{*D`JB&r-Qq$V2jHFO}1I1`q{9j}Rn zrU`ZJ*sajCF6&blq2h3DMtA8YaXYQNz+NJpvstQs?^mr9xLgu9 z3rBrYUc5`6gDJHwKcV?WqV5z&(P4ij%xwE2tn&Au z@(;3Axw1;x(w40KB*NL9w!vb~TQZ*y zoqN!pyvzSN7%>~i%N@1hZCk8D9A<#4`I<0JyVWzYOTXpCRYk3Z7@66}hg3vX;peeLd-gThMcNTD1X!yNq9VXex|PR4L9Cn?K4V8{ zVDCU-jxJ@6uOFou$rhpRzhb{;Mp}$g}{&E3$DFxAG*{N8M)q?$@?tTiftZdAJ zaBw2r)F@j(DAr?BOU?h(BM-8jQJb4po`{g&{cfqoM?jV>2z$`@Bcj~4@buw7?wL>U zcEyjA>?^?r@78Q(V4Zb2JJBJ)!-RLOls1AF-|w^Y?#mdsy(_ua|1fXg967nEv7a(4 zG8ea(qU*XVW}03q2rsP>G{yw<`Jk+8e_J^U;7+rJISIfOP%r#SX^}2MqVe^*1m%M8 zF4PYgDUlZSZI-CvW+q4GFjS>ftsVh-?aBmWRAWv{8Xr!6?gslVxY2LrXcJ!#yE1ez z+wNCd*mo7D#MEA`)h2B{9vSoK_oXd{=P~jz(t17aMoGQcTEELiX_j-+ef%&x`+HN^ zeZ9!}QDA5i%cBc9;AN4|91~GSNuyhzSI=a$@FvwKtM7Xv=&cxcVzK9AT{u@oRt`Hm z!0MZ~XyU`GkF3tNco2wru&dmiF9q7CiB+D)O1PyiFKov8LwC-r^!?PPzKbiO=o`$l z+1%}PX;2J_ebP@u7kwZNaVw&OeDKml#6kDa)+VwGap{|Z=yWSz&Ft`T-JRues1~;_ zZSt(H_5ohe^C$)7hMf1@OBp?)^x01_-a?jUA|TjNQJ?7AAvAdbyZqHf`{Sd$XFIp= zAe&374PmqQ@Wz zJtO-{mgI;tUc318Wl43pQGUPYA!(d*{bu>~+|g6eoU|7g)R)d;-dlF(_%o0}k2KYN ze(M71ksR(Heq3zWXpbQehfxzhu;NmY*QFB6#{IpQW7d~rR5KU!som4C7;f#hqU03c z-IA|y5@90ZaVWmPSyy0a{0cuE1&T6!!tCj;$gL%>W%ysuJwW%I9A9zZ&<2W?t>h6q zj??b@>`j8lRJ|NjJ!W09g__-({D!^^8a*Og^!F<{w{CVDx7!-s!tJ>AJhc1~cBX1x zRfG-fW#!yVM6bGO`t9HikmnhO{=wrQ6)glJhWMn?BkYwAF#K-!QrSp4Dhs+ z@OHrXch4f}zro^9J@->axA_zouYAU=H%>P@?R@*1z59&pCq^a3hSCw=Yy!*7X)7ls z(gKdN&;C|ZCm`N+UQL5zP`Z$VZmK?#2*1j@o+!Lb3CPN*8xdy;Xk|J>?^+#~jbixY z>no8O?B@G>3Zt?SrP;ToYBS9*CbBLK|1mw^g8zr)cuii`^=THOX3O|$R_c`b`h)ya z`Uf?kpcz2F-0Uv^m@`Dz@$vC|qM|DKujYZ$J|Ks_8I$p!r91g=7?a(<8%HAoFu)9| zWYn&&ukR&iGL)YRMCN5?%~1|hWYG!$aDk?!nQ%eCgQkI*;O@57Ms0iH6O@#cJ#Toy zlxgV>TcOJCAxycTe3+jmShNMv*;NLPda22$iX~K<4 z6-6_wEi7`*xn=52wk4$p-w8Hu)qxmLGy`r_TDID|N*|+FGV0&vck@GS-ayeaLj$(R z5{1?)35BNJY^WSL$Pa$iW}Ph4tklZ8DCOcgEJEi^Y=6g?N=fg{3oWkSBMBSW+wE23RRtU?ye%TdP-GQ^?5gW zwr^>u#jhKvTB>K|?*0$Rq&sHur}uAnMD$x%idm1^34kE}#wu~E!BSyg?7&m@j4_uQ zl6$Eojx96T9FS`-MCDXGYFEpZ=LIb7`K(Y-u^l^m68NxvEe9S+1I_O(nYfSX5L_{z z)NBfM*{Y@-UKQ!UOk8LRd^2T;Ujkc0={gZSkCH9b+mPJU2H!94PfybT>HtV5myF7y zJk}4vRLXC4+W-c+N#D%Q=yz;t+v`yL>+0QAZ4bc#M`6amK`?#B4J;Dq34!{lS4AIt z-ZX5HI2r5evL^S=oZ5ly6)WpRRB051z`@Cj-4>n}!!0bH+zJO!&RpudNlHFIK(u;M zagY0NC%yGR_8K;mP3kV6J01^y16puG5 z9c#v+j>Q41uCK4(_IOo}((l9?jGcccsLBv@YSa2_VI)wcbQHeRDaI;(;qy*Hra)_B z;C7_^d(TGoyrI>BA}w+G6`EM+kT@`~KN(rM8@y4U-|$X2l!JqIV_jYm-9bjL21DN-jaU)3hXdySfr z1K$aK`L&yHE_|?1&&5gnM88z8aer@N;pxP?B=9l%-E!+BE;!oiUA#*JSOF+MwdsIjc6KTq?I@llp}xpWk0gUAFCLm zS5j?FOX^gfpPx_8L(?VaL`xbA1&`fIJgV2Ve!8E$cywLe+u@%;rF}go0;T;Q#lrN!a`&Ga2vO6e7Y{fhA`f$tkgf)6F(oeb7#+7Rf@xP*h(QI3#X>y z@mjixz;@hCF-JY>-fERE8b^MrjJCT#+qu1YsKweVSNqOO$Kjs#loBw_jGd0>m;J3tZ!L{ao{&mRKy>&Bh)Q$tu&E_VZ|7xwwW6|58 zN-uu-)(AgqqKf~1imf`JD2sIL6lg~rYa93V$e6VpQ`MND;0T`zq;U~+WP=w0KNk3N zU)<<%dfR@XruouYv^fGc^_5UU*?EqB_}=GN&?2$xZWMagL_A>gzjK2O{lTsbp8 z@ZP1XBK?BbQIZ-ZBlO2hzQ3f-tS_EqyIXyW9{T|v@_r+*JMgBom34LFvB|*V2BfIM zSC*F>&hbnB@-$l+@y~WI(q~31A>!h+*b;#UĄnYm0knPmTM_5O*$L!#*D=oyhG zv`V`)Ja+pmO113v3XT)t3PKsRiZi8QE!4jgM{M<5gk!J!#0|cyyzWMT>O0R z=Dnj@ZHZV#S7uL{sYY_$;#R7GAD?Nb1H2gcNrz-FGwQ8fg)Y^FjlAkTuzmERidBNq z-9@&9&y#zF`frcgd5nrPH3Z}~=Yo66Qj^E1vLA_rtpuI;(f+O0Dg%`e`rqCzdaIR; zu9vyxdVdAieU%bLmjjtL__#NyrBv@;$9FNLyqml@h|dw_SsDeEmISdFRz*bIa+YmC z6hh8jJy|8+@rok$Iq=IMKx+|vo~SY-9AzmS)w@a+gS@Rppk%H=9;>Y-j#vpQ)U>NM zf@OfBTfI)_e^5uuJeez{4N{bt-q|L>$@oYN65LmgoV0WWU^(bBmf!YyO}XeR6aHf* zZ#78RAA12=T?GLG3O0}FeI#Gt+MT6v)=a<04qa_7@9^Z(DkT0N!rnX_>hSyH4iy!V zh^#3g6tb_Agf=9htRY)u-?vGNHB_?iWQmYuU#7B5h_RHN$vXBiwy}(v=lK4fe}32X z`##TgbzP+<<1?SneeQF=&pEI6?A)MkBe+^cX;`($4?L}4^c3jcJ zGL5{aqcFNoXH5lrxFGhnmk+6RP#>Riu>5<5MOB

      sILq02^tF*Bqp{eeYEe9WhGf&@w$IXkeCUt(VhfkR2Nw~AN#@r8B z9yxZsmcUhP?Orn)QSk_G)F2xgF`Hzk9fg0{isRjEWjpeqP+uybBxvWfXnN4e92hE- zcK*T3E|_%l-j%p7&Tm9|9(#^_+SFgz5 z*h_`GHtklkQYNjHV^r*gp5InJ*wRw^ZFHkqF)guePrSvXA^c2vNNKD4-X%3Y!t<;f z`QB9$oa?kQDCxXESa^G8SgJTuOs~=Fh>nDi(uUuMcQ2(J{=&D2yFHVqB(UonfV|Rf zl})HT{p#BtchLaC%T)3&=bUegPt1rsYxwO$G*){LADWnuza~92D_T^@y>H(_HVKH4 z=V9#O@y+jpa?SX+g9B)GL-~Qs!PA$brtUCgr?ikTprKx8V`Bp!34Z)U*j7YNP3Z&S z30kTU3kmnlD}gt9j)#2dhyC6^=gwXa7$IMPqw55H${#;^4}d zRdm%eCD_8A!}A*v`b0s?*EK!KIgs^foJ4~|xt;R`xF_xprD&UR)>?g#V~_cYB-6lgxx(mKXT8kRQXif^F&^gd z!v~T2Oe+zW?Gv^VM>I}p!AJ&SvbBi{K@d z4Hl!un>!jNt@t=ic~yLno)ph!ogq)LDnvJ8`DxW_=yiJ;j===;iJu7wZKlHqeK8~& z!CL})f1C+J;oD>rB}(*cvE8#Xl%*Ra6)RXbom7O1M*-SVSWJ|P;wcoSy5Ck1&VfRx z$bK7wPuL`Xy0OO2LsI!^h??HW639--+@=WF>*}2TNEPp;XYak~;Sxt6unpRi@&@>Z zwegBa9u%R7P`mMn*+%#RZ!1XOG`BLcx$+J!ad$~G03k`<$@qUI2Z*L+IVP9dtwuS` zy@t4rou?&w>bWTNs(1xKzbHGWrA~*O^{~>5yUUo(S&5=$j5;xSipZ7iKSNj)BoBoL z5!?L-Y;<}0;Ka4KI2VYzl2AA0j@qyBflFj)*gHWOy~tr)YSz%6dnX|= zHPxgH#Wa>536D?ZR7P6ZiX;TQ24ZNo$}NFd5x3I0)a=D`jWUw-G)>|k`^ObL6u8Nq zs2$nG9sNCA&Q0SbBL3F)jRQUzT7IH%q*?gc!cXu<*d(;|- z3HrS~9nVYsM&-+x$nG_-4HxT;3BnxTxrgNMejBPj1D?lT90Ki^vFHY4Pc!9cJR+4> z`P`qq^|^_JIc$#_O^*Yba>cJ(Y>omI)Yg_@|1kETauUO%x$(SM;vSEp0?H@j#yEom+9& zw_fL`IR785g#oiXQ2tyw^#26w9@Oq~#P8z$4mt>;}^Fb^84nUvZl6uHJ;bKaAS^kAC`;n%fC0BaPQh#`u{$vWkG}WCtUB$sW={lsCE*#Ozoj*AcfN}@n zzDe9^K?LE&0|GU-aZWWpYGSU!zjS@vCyb{n(p*xP0tbwkgmH58@Oc%n=8+O2mO%LC z9S~MhS1@Nr^65d!(&vnz8`gC^NZS=-iq7h|?$Uh)eHn9puZ3T4?$D#%!1d^cKOW(yUys@0oLT3H7`^^gMFOGL_?Ma}l+u$W+23}eqG zdrWA-{?xhwUWpgs6%Y_POA2!T4m$@*;xY%q57#)SiVAW!QMzK-5jQztq?G4}n<>Eh zgH*&Gjj@i%{+u}FHzh+h%ULWZrh1y1d#3j4v*!0%JYG82->geL)?9q$z6$011wr%B zM?#Z+Jfn7uXxCcvE8QbzJ@PH3r3IyvglqD7pE46zv9AZKsC>2j}dXvE6(r!a1rA#@eht<+Gi z7dhZEYeBqh`BOYwy}jAT+2jCul&E^?DPHX4)NSXIKmPUO@>j^tSmLn&UUSo~;Gg2( zPk=j&VA5^f#8DlAI4J9w49uJH78RRjFJ^nEMzrF_eLIMOqn!K2hvH6%>H6)Qy{_J( z;F8)rr%L_z`!j=MpJ&eV?*2PGJI6oKfz6aq)LPuV$aPWct=_p+!#BYV14xozbXTWT zXUeW{`pAZvcXHw69#skMbfJn@PBi|gkj)G6cLLXbxGR%5@kPk4)8l_a8m6pK6_1n{ zBP}mH#rdFG(VIT>=*Tm~#n?IGWX&yg{mH$FKAgWh*5*jAdCI~h@8LH~xCSsIVtn57YMi@gWK8sFk)SC?e6Y_guv>YhGU&w1qhWa)@A z*U{Q_2Yl_N+B18_?%5TN&Z4dEAI7Jer?O zx+hFXo4i8V~H)POac&g^m7*a6V%nrS8}}rN zqBI?ft#jO?yDpMB8XWq!xd!TDIL#?71N2ZOU}Nl&s2!-sW!0QCI3KDYe%)retR%d8OB^m9a{ZVU)jdfHk8k+qKNQlN(t|SVZiOjf1w^ zMM%vgk_<=c!u!8A5YOzIt`}|IA}JYmwB&3>bX5?s`);}0$px}Hi)=+uL?Z?gM`Tyh z%=cEtMul#(Qqs1`*T30>4PR+=GFq{6dB%8O{(Y<_D!6bV=v=sIG2-X8j0l7p@0icnihf1R zXBl)cR7$WU-c9{_O14C)H&#Ri$D{1`&6r8iZ{NugTRqFFb>Z%8cb{+lxsQ4x6a7W6 zrix|>Z9OeF{zR#JyI9Lxyx_`W<>!y}z>?6CSzdMFmZs6@!%-?EtL8;7F zMK}Hp#Eoydpp?J*I4$_{sARIC%TA`BGfB?&n-N`py~ux3IShyWRcz&uKCYzEC&i)< zlhjHhHe2N=%no9gSIT_<=#XRd@3tzpX*Bs#d$X=W6i2Xb^(Ep$rfQB1XWbrQNk_{2*z8Fc_0KE4PtPm z1YePH!+n)V_})$x28>Osd9H=tV=Nh*{zPVYQv$KHa6v1>Jfc(@a!axj$U)e9Z>;oIcw-T}oz$Ho*VgN&P=xh85ozVks~v zsv1HR*7sK@q_LwdDZaSZiJ0jj@h0BZ14>`D&1&sGNgJIYw!n{?NgH2E7gr`IA|h zb4_b-MB=RvSMgbq(}2;Dc?}{$YzYwWGzq^yvhEhN%a zLmW)UdGdDC)-ta7q*qM_YNErATQ!f!`1y#An?VhKkAI47q#?s6 zPa~sGBX-1Yar@F?*TtPrG3p}GBO+vR?TvJU$O#{k`aVcM_Q@i{BEr-x%FRqMp+2b_ zt-2mdKCV?h{zH{xQ4>B&K8-PXi*n_9sk>qbwfT7jA7wQ~Zfk&|6A@E?irA_qP6)kv zx3B(ENREnz{=5mQd4{ro!eswfse}u~ifgZq5*!?walL_X=r+W;^)M7ZXqg!`nkMLyzd29y>ZN<*9^Q${l1AbpruPAvx91RMFFMpxdCUalkF(EV-Pd(%-ZC< z?bUtx=Xbm!?PpfTo(fLWkp==&Ozhl``Z>HoWau2OWN|BMV%$NTr>OyVHlu1%VpNO= zZpa+F_j~k4G-HF+umPN$21rk>hL=Hm;T@OCD~?Bx+KnV(NPM>B4xQ5vaA$Y6cqis! zNLHWU1#XuuT2(0J5tRmDhe8sapz_?fl!8ta$XXQN564dQA}RTUQNn2QF6Qb^AmX)U z9$jGR9)~W~r_Je#eYk%5W~&Pkv?G;u%d9O;(4&xI1sc$#l@V;9Y#$>qQALpWrC^0i zqudB~_48>o{Sl!cGO~w2_d$VBb#xTMJ1!w;0)LOv&(;R!NWUoG5tfsyuFSViQ1hzm z8vZs0)lrFOx09+tf{T~;Zr^k-bP;z^+A&#Fr;!uRuG4!InWqXm|9tIgHRybzJO4QE z8($&MVq)19n`w}X=CQsT&-kzUo-^q|!;eCs<{|hz6p0DPDOu13<0m`KXI>-sWiKJ8 z+_|<_c&7%j6m{lL^yDb7@Ccd~bktuH+QvG_Py(T zWn`oanmo4Uu}|+BFQ@tsa5#WWy6y%tnqNVkw+X;?5OlgU8PFFwv4Mo)YqNmYYP{S2 zTsxmK(7o~ND4(*0pq(E^P~ok&9+3&Lw-htOP2$Pt2M`+_57qW+D0njU1!t1i3r@yn zO}yel?0=d`T>fB-mc=$W`wTj){LtTw;XQE&SsVrjEeyNR9|QUmJ3It_>%)I%pTj>x zGExLmc76SLeWk2m7`n;Gq1;F5#*`MSV#$cWWS%nCMK(D|dDg3j4@5L4R>s9P*w}{Q zkPq5|aeX#ieiOJ^AbR;4sw%Kckp(g@f zM2u+tRsoyf=$vWFW;CM%Xd6CZ=Iim+#dERHp3x7A`BqGJnNlOFJ0((+@TGrPG}#>5 zG$1dHu}a55=N%YBR;7pr&JyJ)4wMLO-}IdSe0bqV?SH-nvd}cOUju^fc4Fl)dDIAU zuE~k`J@<&~i$CwA?&KnW!u(DX8F*(0p(OoA-gCVFVdX{q=I73SP%I${av*9G6Ae48 z;?Yv#mt(!kf3%qIhTcVP8@6QxC<~HT#NH~CIY@`3v>Ilh+E2vwk6RhIDkpq-1UGYg z?_i|;tnZY+{MKm-TX@@4qU_eh)Si~ZvP7v&$%b(Xh+vN}Jpkb~_wI*Zt<*G4GONimc&K?N?8fPM<=4%FIJESVNF9i#A4D?U zZG{+oP2j*nRr!CCWruRb8jO#i|L+j{$#2HL14vbJ6mulUfNM1cjf@W`QlvlJ;82c7 zY&eK@e(Pqn>(X)Gzkuo*Wg{oHgI~kC`c}gp?b*E&UfX|-p~s{dFs|bL)wC7;JnjK$ zVnw56-Q}6+++$WWe-WR1$4?GTx*4gAgp6;rcNr^83{gU>hD9XpD@`TquhA<L{cu&*!ZPSH>ZhX30z_Wfu=N5ND1-y9*jm%{EY0fhAQt5?K z(`N_DTuqwtY+a|r)MDy(;C<)>s2Y(COd5rB2|lE%zo2rhB`UT#O!WsY~?|)jM{S(ZJJRLY#OH>=^Da%I9@7D#PiVB|+ zEn>E@E#`{k^*MZY=wW}PEd0qkc;)5kBB(I#E$(}xtV+Fj_M^EeW80X$2Gn?E6xqAJ z!3mdY=r9t5;#7XngZCa#*m_D}LSi9Ik#PINGX{if|E9FlvI1xHnde1M>omUnGe_m2 zua0shZT_d#kphizjrvN>SaTH0__8(}x8eQ>h6MJVN61}IVye*7bbt0?w9(Qedf9*Zy#kxe^SGDx|HbRQp#+)F1Q)+9?ydOT`SM zCOC2Lcz7NZbqW00=kP5D|Vk$C<#Skjv zrH&qgT6`WZcuXKoyvLJ4Zy+48<*8^jT)dVThW$JN;{{*puPscUUP4aQiT9oD{^L}C z1D7Q4^5M@vA&bCwtu2P^zGI5_q&!W1e=pBg>`&V5TP}&bb0nHMYinL5A{Ku(UxR-nCvvC2vePB({woI(0DXD|5*)XcuS4 zQEfB-eBa-N@;?-C&;Pm+f&#zl`u-j(>2&f&u0*dVK1iONa<=$)M=)uhbcDk;L-1j8 z3p>}555`?oMN!53{R>rf=m15iH5)}~oNaM>ds6_W@IHRsnX#Hv*hs4Cm!ut?AO39a z4;$-Gzbyy7dHS{=r##dI9YrVNY`Xty_E=f<7F%v>6LAKW39n6wnfhu(Q|2MAPg%Ne zIFTdXjDc~!i|M7E{b3WZ)EBgPgibXqaDu<4=TOCr46R4xm&BK7P#<9JH zvoF@TK9T;_t|wNk4R_n?QCbBb?e@~@2F8Rt@A0$(e(3${9}H2UurDZ@c8t&SxYswp zqVKeUW{R3gx&7Hj51BhpeR#t?j^;jUE$zzrbbL4p8;+rZu)o;l(8R>Sy765d6C?h` z8H}CoNwb=k?^doiv|Fus#0=feW0&7iuwmrN@g!dqhUtK&Qh(Z^shF{=F~?G6A~DE! zx%r5nqktJ*Utrm3Q(M~W;yfX1K2}hdOTZ#2kcg{X zI|$5`jY=BEl020MF&SFmY|Q+ttcH!?Jr-w1OjDlSF!L`}Q7k)UHLQWP9sLdYuXmGp z^ViQ#?`AsN9q=A8kLdU+UkGc#IPd>`(A;$63S~3%2`&xVEP^pz2}Q+@PkQ-s?z8ke z0qJdRx8Aq$6R}8yo}S*pT%-vqD6QNUv$oNv17Q_JE^I`o_&-cU*cN$&7^sAa4PhHG zTO3x8Pp2?z7vHudiSKA)BjPXJY-%ob*Vnv-Q`Mh;aHfp&uOe?G^fcRCnGzBHw6FQ2 z-kZ^qpE+Eg*KPFHo2+ARvI3#Y5ayhmiuhDTWbXP~g!KPrXnjYw2GEgOM6URLqD z=T-4F(K@?q_-st9iJNg_0SDpDSH!@&cBQlVH|QM z!*!mBJXTkKZQ|X4B>qx^EB^Jp?1F6kMa@Y6z__Z!M_&+5Z5{w zvv3i;mw-uY!`@n`t_hQPV%@pN{>y_%SH=T{Y{86x_cb;0SIirsL*aZvhwJjNG|ZI! zpyhpnZ47*6@hc}rr9Do>&}VDNwkBv_p=8l*rk!=1G%G79FJDtKHMT%?m9H{N{3B`7 zuppf*0M-C207iVnYozz2DFC65kk=-^FX3BEEXWF5tew z2O#gN+G|rkJLpxmyx#om660q-N>%)6U8*Ei^^WaXpQUH)uleRTo@HnpWjZP(>=Ue$ z)5AZr12Y|8YpB!?fZ2^fNzK3HfIpe_s0eqpt?btQ)0#qoQP zRac&(iqT7+*%c(q&ak0wFML0x(YU<#DJAQbL_)(kqC zw#VfLuKY7NBjb8fXv$#r7#HVdp!>3`_IR0}>A#Te9pGxunD5O5SyS4@LNKyvZ=!$99uf{uaR#KlqNZ!+DoI+kP&I8b}^^ zx$WiIG--K0FW=zr#4l@Bi7!tRmnPiQb?KU13|T~FXf@!70oct?qLZ?VuPlUKJGO+_ zX#?aO$*OF~uk6bu<@-T(RIv?iq~_LC{~3ETc{N*m8$*^uo+1YbfuGK@w|HtZMhR%~ zuQa_Aio&J!go|{>Zw;!Wgg2p7mN3iiGq?HVWJbMuy7*m7A8P#p!UF5?zyVm8@$cYI zE>Suc;X8o32%lv4GvYaZhBJ9E$LQFG2h~M7*TOq;aq2(C2ftmd0yZk3G9O*~Jt>sT za+B@4qlVw9ki)9y82EN?1Nd>{U970e{;369^Y6|N_)zQp8fGvsZ=WTo*KwqR_}#$3 z(u3K-=LJAo0lIzTpI7&LOY&+`(?l@!$PwO$lmI*Ja<#d-@RA3mZ=&GWF4B zwc4$LOzM`891qZgOD$*L@0|p0$7BglHQS_9(heWg=0kR0C%~X>bk`E=S54kw0=@_! z1r>%F>U{j3|K#QaHLpd;;n^(?g;>1B;3OCV^&IqJ$9GtukLoC8_EDKvV|-hO?~$fx zNS^*Ea54vX)YVuT_!D~YGy-(jcZm?uHJuq&5<83CCkAQH{60F-XUhBPT0AjU*=;Sl zl&Y+=Rj%(RV6IrAGROGssw$mUh=KJ+XG;x^eixWCY1An;Q0x0Q=!0X@&tAi@@VhjJNJi$c@9@>z zu-dvFeeu}6|6L~skTVa$-vkYCW(sQgxX-;B9ITO~gK3HFMr22zNtvv@!TY7M(6SJL zFCr&Cm~S)JoQ{cQAFs+855<<8uIB!8ITHeb^-;3kzAk00TT8bWep5#7*a5VFc6QN*`d0tz_ ziE3(ZP>1xs& zsW2u>odev!e~WY1M}xmtTtaQL3X7>|{gbCxA)EvjgBFJkYhj)h5RnA>0Agn>26XZQ zjfqM#^rgr0CFPpm$`|Xai$?1I<(|z^n{J0{594$Kn}NBkP!tsuUOD zz>h$qN9z5QX8eipn^gB)8STTRhW5-}!ZXm|lh&H62NXSkJ>k1gFx1;b9Sr=pN75_p zY5)vCGQ#4vZDeD;U)WT^$HnWsdl(1`lrkpyYF__hc`mJFr4rc~ugb-UT)mxrEnDUv2qT!l%hO zK-g-Z98gi6X(<)odWNmb0Xk`8jB{1OfFCd!-JDtK^rh0K=lC@&=&H=Jd^fpX$Lc(@ zr|SMrTwSoHMr(9TPv0qPuC#nY`-@Bd*8C9WAjKTsVOuG%%hyY{-ReW3CkGJWFMe(- zLQ9P^h3DHxmih+P&bz>y>3)A})F`QIiDiDD_~R(sA0-;HILzqb2t|Dzxt{WdVx^p-TZ6;r7X5R9Zr+B831?lcNX zxNrefG}uZEZ#^B+%lDsq@2#p5bMe0&31Cm06E(5jDn~w7MyCD#F-5OJmihhji`4I@ z4_M)YO#l6SapJGYw%2+k?{!CvY0D*y)pP`KymCgHuD<~CHNd+gk3T;n5!nQ}PPVe* zYul8XmI-(ru+i~$r0N!@ zhixo=_RrY|rWf5;4+CK~XW{-K4?#kpxK?COkM8^UGW!|fpXV|q71h_*?5PiIN?m(n z1^YLvG%OM~CTJf4IUk01=ReF2wqIQWSOfSJ2_4sH40{(xt!6oOmgWNcYgLk0k#T11 zbSp2qC;@1anPSLWFVfp@PMzSBNzJooiM;L9e4OiHBLlT0;lFGd0xpUy89uZ_d%Ou6HAgz{X6Jv+e1RQ==e-l?~C-*MsO67c?z2} zzXs#YoUmuA(#(JZJnZoJ)z)T*lo+ZuR!pj0EHJKr!}s?OiLYoL4V{}4ad4i=9CCC6 zhE!pv%nt!>0Mizv`<~4I8kTFl z7#!1Qy`XnZr~Ty*%c(~IHLp3}$ocP&@OIkP?B@#$7gHC`C&&Hd7z!=q?A?ar9Ip1t z!9*flMK8PMCYKoE=E~p&KsyK3sqg>nkjvfS{>rlEn!;M&>h{h@IZb^`OMl%LO5~wzjQc!(7UhKS&FPwXXl~|xr*HRC=mTtewR+@{?cRg zW)AItSjLR+wFG3AgT?YIZ%mDz@F`XRc>(B9#foMRBvsv>Fe|5B*x*u#93XI1Tu#16 zUGGIxs(a-6hRG>uz9S*ct$pv$ZaAL$`v(GN>YC_ba;tgd%n<<8CCBm0f8}ivKiDKV zQLO`>t!VTR3W<^m0bbqPR0v&ba<5bX@&sN~^=dNQ*GXP9kRa=_e7nK%OpNtVCnJDo zUuD~Q%;r10XKb##R((G3dD8!+(bcH*4`SI&BMy#tbkff?P=xrplN;_Xwx7N39Qax! zr4N_1)9hS+;FL8T%D!KTw_f$cn~>egmD|6H0)6Ed!19wT8~v~Pc`;qk`(C98S@Pib zz$$S%7sz12DytAc;Ot2+mcqjuB$^)``}W`{%MsMyb90Vbr&hn0l_kv51u{w^Ud4Ca zwx#1+Nd&wKBO|Cem!kMy4VHgARPcWbmj{VM)hDlA`7`Ncy`M}60Coshnmr!&iN?Cp zZ+@PGCG+eLY}<>J5%K0?(SM?yu=US=r-Rfc!Vj;)%zc=u*dP)bUqourzs}r@Uec5n z1(IC85~IaASCN%_VS4HL(*CczH*acl@m1gxr6LE)jZN$htX+$zo1&dza|)uMWxOU>AVFu@)PEbs1gL z=CV=ZYd*liuPQ6tao^^A_)(lb08*Ul8TD>Yum}NYc?4)z{uTj}dUK!XGyffgg#P|F zG+?J;Zv&t_*Tc$sZ@VBS?3nO`$VFf9KXZVjTJiYrW>&78u#rC`Euihp>u$PD|L5op zZUP@I`c-xHf0Nv(?m>_(j_cpAvS8{?uX&-DtX6&(%z%Ic^MwJZ>G8CB-=1(d_)vF> z6BewOdbxt9ZvKlwwLN{AS9C)A{Q%N3e+VOt=HEk5 z&YKmL(O4>dcj#X=lBNUl*F6s_%tlK5T?h(c@$GBLi4Kd@nNWCk6Vu0#RT`+D3(-IQW-YO{XD}1_?Ura)Oxj@fXi+ z%EK3H7sU=Kh{F-@sA`xo$d-R(R$m1``sd_%3dp!eHM)D{kNK4e78pQ0Jn|j(z+vOq zD&I|EC&2K{gR{rnr_Vslnk*rTCU@o?z{T;ip8sEX=g&I-YJLZj86Rygpt~h~kMaac zzNR$;`-qRO{i;+zEH^qIjxC&$7G5Neh_BjX%)nDP>tZjzhG5V8dCpQl=eb&Ku>H-z z;FEc-9&Z9pE3CtEsj3UdRl=6r4p6%Ruursdu?xt19a4|eWN+SjpR5!u?RO}@{@VWN ziES@i%`_Cm4ANwuPw~+mIONF(+*k0-pG~An3~BrK?_9iv<83c1F_V11E#t#pDb1@v zUp0BI>)1FgN`ooDpKS}4zMqehe_ZNx*4nG)PVMEg_-DnU(VbfmI(Wmzg6VQxi?j3> zHe0&UsLO|*igor}>U>dX!4lH#PLny`y9#+hexY!UNpvvPB_=VaQz9Yiv#V+!PmYGZ zxV}Fc`3IwnTE-~S(~vY?Xa2pWEB$SHT;#g-$v2OqmR^c~^xXu91h023&XiiaC;v+R_nLpj)Bs?tVg+f8sZL4f-=JMMy+%ox0I~HolXs0RFkXeuL>?pu4Ru}b1ps9) zW{&n6Z!Hx=TE)uAcpz#yS)n^Mg&#>j&)&;JAf46TpJR8XVWvEi#f5)gQLz^e1S!%dU8P5wC&G>U4>#Dcbjc z9O|QnbY%zGZxV{1IpSu*))OcjL7^>D=5F{^|O#pES^!ASHoB#7N3yzN?b$cvHCwOa`9|08 zN8-QloCt(`RTXC6K@S&+;<|t!(VUxb%!9hvOUF52O1V{G!*az?(zf#*vS_xF-3lOJX)1;$Nj^S|C; z-%hOg8Fha3x+5^sTYs^9VJn$1V52j!RWrw4hDypAU1=!hut*x;(4DT~20`#d(_3hX zWe@q-chx(h;_N5-p*^0gjZvJvRtE6@*6HhQQrH?!P>H3J&8^SNf6$&pnlC0R8Ro*j9HA4{91ipZ`a5S)lSR_*>>nG~avlv~xt~l@3qJv@`ji|8}D{>Qsl6*Yq9& zA>E`Hv_x4V;}K*GqI1No%D?fF480n83$<`hBuZF7raeN-n>NPy~k&AnSk>!WAVb@UkJUJ*67S1%_>8;N;-zEi+=*@L8 zaHyG-En=>kjE2H;rwH!(^FL%o5h=lDn+`6&=OEZThrB1pbzTaN=62!B=GDz$bO2^c z{~jbjyT|kjlIw!vxwKk6J^mvv!~xg&;@s#5t8aN-J;^GeaD-Lf<=FVMjCfF#d<)zJ zvT&hxW_34g$zbsn-q?0TUTviHGUoK|6%8l(1QyG3$V*zk3r*zedE8zooZf(>6_&EQQ7Jiiu z!dO;5aXhs!|0@81sg8pO7+@(KhR2BnBL;A=s-b%%5EK7_%hVCm;Jb>`NjXG!4nK+RSeMICIR!n2N@45VPKwzcr;(s%8fRuVZaN49Dsks8a+ z(?=z)9s&PS@E1{h=CQwmUhH0nL(Hr6D2cDU<>I1g{99e!c~9-yq_U`kinP1!pY2NQ z10VD2wQhSW`Y70~uQmR@LFbxK^BU*tlP>t56AXV!?TNPLw7`e!aqD`dG$cWU%MYis zy5XMhJ?)Rb>}JVPR~o-G_jsa&Og?x;4wA^3>VwyjFfUvg@*1T#_?%f-VqZ{Ln@bq? zuQ%Q&7H?Frb&YS7V-V}i#gz@@@GKmORXrj*eA6_hs)olu`8q0tu#K6aH7b0(OIb@8D2Qhnd7LD7jhl?RlleVf%YcsYwWBrRPSCLy(eb==c ze;E84zSkd8<%297u0o2LXW$l=CZD0kLlJwwYu#KPZ*J_+cH_EZQtGG}7#@+#@ zpWGxL{4YIsQ06)|mqcO%Z-yL?SvGbb(&f7Wdw?J9>tIc3-W7WM(T#nc>lGj5e5fwk zzIv}%sGWd=wB^z{h^j==GSC?XV)^23FDGB=WwvL&KzmKs4s&;+za1X*lSez>0#Mj! zKrFkE1GHN;H`3d0k%L}v$lmRy0hDfPJ9QjeVj9oxpNz08tkrgdN|43d?)CZKT9CY9 zNn5VZ4jeXc7Soa559%L;ZC-V!0V@ouQhwk6gV3kLkHD%E<}ZJ*kb?=A5T2MT29EFQ2MDX(SMu-nLv5)c4*V z7Fu@hS1`Oh@Q8BoN9m)TrLXDt^vXXNdwb%Rq zYgC`4?Qa#rSEuGr7H%AC<={edfl(B*zo2uU)W%(^v71bC&jRur=FuC9TB&Q)jbqpE ze4LIffQFZ^N40YAKPmq@0Oydp=`OPJ6U8fd$|q!-bHJ*5FMHj?;-OhUc~D+2?to;a zSCfv>R6)9zB}GrIwZAUvy=FPGn}OW6*RBVo?-os`8GO@1kBeMehmI!!8gn_({q^`N@+z>Vi^MRDnAZvw?+d?--XmXJMJe?MS7fA z2;wqW*~}CgI)DppJN1EI@&Le6Z@H2FDI;aUUDTJSWN{^#=YBCu+q?aO+F;Z4rcYOH z4MvREBmiv$OO0FTI=jiMsBn2CYuFbjD+_PWJ$ssBP~wl2JbJ^q%jG!ymCU z4a}LdL4E!Q#%o=pLzkE>m?mqlsIoITt#-(YWgJAt%=aojh?+efRf(0Qj?yT{U_i!y zdle1^i>=K&DZJ~Q3Qpw_*^6*c{q`#0SpA?9R4}K1sjysZ{`7n5uLx&~VBGAgk>`fV zyXNj!0a?(*;EwAyt+eHnk>u6?ax|n3OELO=Js9jgKA7(w4_aWz$)XB7#8wMUe5}6MZyeR|ck5kl%yxWbke%kTSu0@*W17DIPms zo(hgtl8BrCJOJfAG1AE(&x~I@z~~`O z)mJ);uy>b%dELth=b@o;7cNbX>;Gd6#5uJ})>YZKgHU5S8YqzRe5mDWX==u#H)7X1 z9TDi-0*x97N)Z=A>IWxJ0}@@2{b=pxLlMe(d87oB@XOZQ+s!HID0X`viQZm4q@59^ zbL5Dr;U&YA0CG~ob|?hePtuenW9BO+X)~0a?LJcX-gs^Ph^}KvWM8>xyhA~m^Rp|n zk`ETN$Q$d}e-(^8>iRQkRF>}hYlyu|;~U#F)q$<;e&wBUizfnB;9LGhY;QzR3>+$V zL=gLtBm#2RUg{a{k02rlD*yQ>Glh=pD0wVZHdZ_p+|433#8D_ZL5NECJz28kr|IYg zM4A#%8bAzT{X3S`gQ?@)Y&SGf| zKS%E$c^*D-et_+^+mEHIVyQL1H%8lOc?Cmg6HNGtb4y_bdte7UuGfF@`G-rQl>LuX)xLTP zHcL@C`78S`X8;sdIsnZK*R#He?A|PA22ilwCs8Nxy*7O={^941$;xjf={ak?1BZS= z?QwdL59HZr7tsQ3Jjf3V^SA@;2c(s&n!FmiRro;i@DNTYaJ~FhuqK$;gRyo~Wg=UP z>2DNAb^0CP#4Y+gjBjb}tmm82Gtc+jR5EZ4TMCTHv|Ukh)|E>8J?;92!~`CNUB3m` z4(%g{6!GFk5$iEXorVUdQqeoK^XG5szB_+@YuqwQx~DnOTq>SF`KeUdMUEVat??Jx zma4j^4u2RQ*=qFPYsjaNA673}_*+|GG3%>eY`f&$ZO4-&CGn~9SP6Qe9}06{50B5j zn$tRBTc(@K=f^O<5_0k4Y0(Z8`^AI!Ds!^}R^`vYyRW*T5 z0eBlCnEmfE0OKD}=@iNJ`{{1oUuKLQHEn)@tigQed4m}h-6PvD@LXPWW_>pqd z^xeCH%c1dM#9vCmT%TWaF#I?~GoC{IV>##g`J?po=wNTZ??#UIUTk(-zB8j}Nprxf zXhg!ke6$HZefa^?VO5WEMOmiE7WnlxIr;WcK03>5*Qqm=Z)k_`KC*8#c+GWu{i=B2 z`_n0#ZBr~6Ct}g`EjSU` z=hkPJM2b{zSzkVCo&T;Z%*^_pw!+t5qYQp-Nh#hFI*D)UN>PVou@o`UM~yPRD~lDz zgsyxM*YQhzF=6!px;8iW<_QWM^QFlP2xWV6;X=zD*0eeI+eJ^y{Q9)Nh(=x$ia4R2 z7LGA+y5@uWf4Dm9sHna-+z;I;-5>%=E8QI;CEXz1gVfMHbR#HT($XajLx^;DgLHS_ z!}tDke|N26xt6+S4rlgx<9R;s-ncu@BG1?xP~x~zZt*tSTWITFxG|*|(;RC7o1cXxw4?>h9GHmB7=bVZ zs7X#wu1c;6NfS2I_K}AhPqNm9nCmUvSQ`3R));#=P{x0Cc8)C>3L+H`UR4ZQy^uhg zlqj!&riKMJ@E1SfQ_7UE%9eTK@QDZ4fVqO8E=Z)A64*Yna^8MN{#Hj(iKfZx6}~GW z7@G>IFZ;;h^H4`JH%Z_?Bt#l-eagJmhTK4dCUie%0AITlD{uj4`XhX{6njjl2UXwz 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

      v`WMUk~4RTnbu-PRw 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 z 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

      b?S-+*3^ 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�RZXZMY35zIYO*4Kr>@KD}5M9=Y< zdwZ9p-Z=}U{{pRA-y8v0T=AKbCJb3$i`u!NKVv?;zSwvV0TGcMyd0;OjvJy;^yn$#RrCsweqXB5W>FX*R>M7a zXvx*z^_~aMX^dI_+MHmJHaFpF*yVDg@Fls&UhB1+KF?ts^r05z%dh5`+yQlJcj6l^ z191at*n}YQ&Afz^FK~k4PxQ#1unZgZq!jnE0_1!jDRJW3O63-g3e(O{W9#Ol>gK0} z53x1IjbbxQ^7UoMB3@-{ou?-woDOp^Pv0QX!boOmPl|^%yu&J7K-ehZbCv>$jmy!0 z>hnT*XHGUp@tv?>$sM+1+H7jOiq#QHa&!ahrT33snX|rzhlbI@V~Z@?BAkAHUH}lm zAfPD2nk9HH%9$E@7b|IR%jR4i&`Aa6n?FHIG@!|ZWx>9aPk%jMob2e72*oU-jAE-X z+cyhkk!e+M=ARmD>iGTTWJ|30Sx|Juk5n2 zLFVMuM6I+`^(VFc69TaugvEhcvs6ignSn}`L-WeZ%7(uKKCShjCZ@b@y6X~kqcCD7 zS3IT6+$Y&yKA_^XdDEmS#w*F_kd5*&*FxR_eZo)~`=4YnQAf4-)a$ftK&K7L=)P=I z)_=}d+uFqioU86 z9C!Y?6(5~Mi2>Z@@oS1y79wA800`*B;L!*MAb4TRO`0;r)F5;$(Th&9e4Y!Fvs^gkh>(4;$~r=GKsMal0}i)+jC|s=G;?#+ajMjGPkAxVzuTX zLZtw^9?vF6t?S;^iln}Vs$3XIKy=aQ7&Ove&o3vwm63)m5?;&USBG~iQ4L+VqT88& zfvMeE68PJ1Ul#Wh4{jGV-pk`%tPdf;-XP7bH(BHnCS8ZsDNoLVN}C3cZ}?qQ<<`## z?gokjRo7|&-zuY-hFgU4>)Hrh+9)6$fREE3X5@)!h|v&QCXM z(vzC17?KW)et04pwF1-9*n^tVVT@UTl3DY#+I8Ub;*6Uj0#9(C4B%x7xkE~$mP-v> zr;XMeU^i_yb=i(6TsCra{%&&=2U&~=i)5K{xdLv$5T%p580o#&g_u!439JBY%Ym;|6fI2c-WUul$ zZ#{q+y%{^ote!Z#FnSDTYJ&Bmn6s@>PFHkugh%j!q}NY;4u{NXwRdmk#PF&1 zX5U{-hE<@JRv_Epvu|*C-A3KF^O0!&G1EsLv>`9(rWe$*uV%U#-Ok%HBw4(Xl*A1A zyE}v=3fgUg_J$=zhVl`lSNuz=T5YRYHpfgJZPFce!2|PfYQ%?WK6u3t^FBilvjfi=4Ks9TJU^Bde;f~UR zxLQOb)P%XDnsBtU^wrOIzJAq)7tF-oD7>r?FNW!DUKBgq_WXWHMrS_SzS*3X#wBZH zb2!sR{4Y)dgOzij( zk_C`(8c@Bng)VS}Pr0(4{etg<*^(G*#~qSNU`bL?orJ!8h&eNW9oy zqb~_InPW{5%%^_U9VQxid#r%ZG_o_~*Lh@t8LN7>LhF}Z<%Daml6!JU561M{%DGbf zu8*G2iOMoKdBM(IyUePIVvb-JR&9H#!4!DwC{1w}&+!P?F)po@eqS`DCI|1k;A@gE zKEbR$D8%QCiA>(4o>)QiqhUd?T>yncXb6WJla zo}#~h7hGfM<=7v0M=?rCe3yjAvo4U!^SPH-&n#KOv;YM97rTu7totM>?5ixB-QzQo z>bRl4TCRp1&VoStfIzbVjbn-vEkbC8`&k+e0TYd93D})S`R0>Gk9vxrbrpa#k);c& zgT~@(UYei!#@{g{?6QdDhvNl>zgx3ZkADq+B}WS~ zpz508Wtd6&x}|e1Twl&bZ^BYc`zT(;z5o6>`xaw%R`d^|qCN^ykL;U|0(?(giqY}C zeYPLN=Vl+9oz>fP*W)Eisj=L=yCXf8+k3%z#x4_zpTIHg`OtEcd}>ag){W5%WQ zV+cs!Y^~i-C&r(_hG}NTSxcvUEJrxGUH@_htWq4cDvHtMB6Iufpf?v@i_+EJ1#Sdz zYW&F?ZZ1!MSDiMo*I!>Q@A8~W>MO3yiY#pBb?znu!N%c7a$+ry>5|d&^T4n3G6gk> zKT3}?ZZ3KK;&EL#r%|1kX#R1s<6Kf17T*rPt-fe3N;IDF_@6Hn??U$d;grYjcO75qV+_V6I1M{II7p@NM zs7Z5U4{k5!>3dzco+cSH30u)(lx$2x+vTRJEn7f&Q|?}uo(HpO_&VlL(+9AW0)0Ah z`v^Nj|2yAF9Ixl}Sr}+j($T(JD>DtI7vGL2=53hVw!RruMzI4P_ND^$YV+JWN$-jQ zF^s24->CpKIcz^PrvmBYW@}TQ2zkI z6_hXjiajqsJBol7*(`kjg$JHunUt#gTIUwDf4Egj>$IY%}5OB2x6V69>=U)I~D zAp^&wC2=ZpTI;JCDywa9wyShZnTcAiv|dG{FPmWcXj5*U_jiajQ`jiM}$Kf8+ zrSwOrwy{I}tZ*RD5*xvJ&=Dmb2O}MNsbNo!`0?nXyE9DHT!%7vVI;4TgF1HJ)2s^M z@l-|KhD=MMLmw|(E-a*~18 zgm`a&uQ$J*rBtNImT%F{qcJl87i*V>=6x5zlFT+C7|*LZ-L=BZ$94MA8o7u2bH{~( zS{`|q&_H&HTgwh+?Sfh(gGL%9n=W5REh9Oxq(h407QkpGq2&Fv*L4_^x^i}%IyKyTx7r{5~^sNh-+iP)V{ zMK69cTx;1~%L1a$wxK`i-i4>LyNm+bqQ@1;(@uN?`Wa6mk63=*+~xnhyNB?pqtf50 z2w@5<=vGWF>hcJ}%bV4I`!B^`-zSU|zRySvG|sf&J_{_`2i<47iRIF+d`)-ww^#NhVt)-Ryq<&{VKYR+Mic+;d=Do$igL zVsk`6rdH(|dM2wcb?-$g0s=X30IB0+jnH4eUg<@xU`y?B53_Vrx7RN*0#CuaxWP0- zkjA%3&SG8eHNQLZnDfC&9@eNDtMD2N=Cxvj^CvODXlQN!5khzTFl@lIIXVhVjCV?$ zKqGoX>0Yc(u8TnKt9#+J+MK`o`7%FBI zx^e!^uzcvNVCl`%g|=?c&Q*Y7y=yGJ-lM?7?>#KGl_3=BJ1ke2>w9M&l>7RR5mR(j z%+nUy_x8=|wr(hp&Zc6Yo>KYaH$^Nt?sljZ zv*V4J%j{OKikW;GA-1&IPWz=;7vKn1*f&mzXTj0vjzs$2X|(^^k?}@BEW0lY zLl4I!KR23WUY*m&<%4g7X@c!rc<+1!X(6oKB&;HQk|gc^B<}f`X?{kdg<~Mm9aoqB zo~ao$lX#GbdF|~9`BB3H-ZJ)fMuR7v=M8dAM9w$7MY$_vG+q06qw?tf&YPvUR>7XP z4!SHV&-G@&zA0X97D;VnWw2jys^cwah*%|k z`ocS$9DW_#1+^TG{+g(_*uVy8hoKs2T_cH{uBytH-p$F zbLt(?-}4ewKxiTNs3EpLW{WHgiYdG|K0O=f3NEs<0J+)a+ZdUSh`Twxf)#}D3XVN@ zfhy#6+WADHQu6~g%)QXg+W?4ygnR@FY?GLS9q8@wpBVrR*m!{J3LbbsH@HFv zg_$!o`nPaJl8Gzt7(SMk#+k4lvXA>3S}C^FB4py?4wj!60e4-~Ds^r24AK2%Q{+7B zpp^KtplxgH2_$N-lU+#(?xsJ}a-M!I?ak98x{3uI1<;0$a;`-7&=`4HH9qxYdDVsC zGZk?z19y*X3oEt4?vQWE^lUh{TMTZz)6xV*`GgWMlbRBI`UptJVqN1id zD0ARH*7*lhuFr!+a1f&2D(xIR`r~s^Pj2z2Jd;*jkNa3$E8Xr~m5A-I!k}2uP*2EG zOX3_yE)*z!o(SE~N>ka}sI|BZy2u^5)Uc%uSbhP@oP?VwW|boa@jjXwM+nNCu?8qc zM2R?m%3YkQE7L^61w{+3gOp~nv^4=8a^Yy_IJ2hUe%JG5rMFU6)@DfGv&oCWNaBIq zM9e^=_*jIQLJWrqcs~c#x7l%Y6jFk-`?D>Or=Vg%(-Q$eh6uh0Y68#iO-F&>ilp@fT2Q)I=ZlQEJ2v?QYvu}tVSA>~Yi1KV2%oI%^TaL~${z@U3wrb+N=j6du znS=e92byaEm*0bU+mX)&Tc0C5cN=IIXVnM8rO{v`G8NG?y%>YNVqHp|?zq3UWr9lH z+e!s3AdLvBRN08^^I+|!xko(KoAXUolZK}JC5C1h6#v|EaG?3so#z-c_Zf!8mlqv-EC{WJb|iJD>B+4G@;4ydJ)J zMaU&;cysZZzRzgHTrye@l(3CCht!yM{x`V~s(>W`@ERpnl(YAN>J!nxF3WS#Lw7)G zGhLsf=Pin<<&OtcQS9b5ZgfLyrW_A0AtT4#Zi&=e63Le+Ua~{Wy$ox^ZsD&>wqmTw z!)oALLX0mHEVU^wandnLKur)4PkP_W{hJ2c#dzoWf@Q2y=w*TJ+7KaDO{3aJYsFm( zM@Z2|VkyCk$M(O67uZ)oJr}CJDa;6KGBo31k(g^0j9E945d(&6)BH+Gf!ODc><>=_ zV3b1K7J!R?2U5n`Q!wjSDdoyS&c4k~qv{-26l~W<&^PzDn;v5-EQ_+d{8(*{%oL*Nk)t+%7zy@gU+bAWrr+PR2HDH*G~?R-e9Tac%rq=qmpi=?Z;1e#9jwSY~Ii( z(p_d{)ZH9kkG{z_K>N!Pl)K;amnx={u9{X=oHlEkX=hwpL&fAcFsMeBo5TQSGp46+I$;pxdCtGmA*1FD2jYU`!Ue*ZNm zf@2ReS!&PN`Jv}c`Y7O3Hi2Y-jfMufu+ljKWV_UE8X*#ZkLiM3?U_}a18rb9{9a(J zdPTVZzFZk>A)R^BJF!pY*ST>?w?%t~GIsi<*aKpJj}84}Mi~v#BSzws_HJjj8Z3D1 zt5v?C9(F`Km&p1dNe5>5`ot++fYye6^$ZkN=wVu!lL){i2A>6G)=le3xa`7FI)y~n z90y|QqRBNTKxt-Cs+@XFq^&h*lbmhL4bg!Oh=?_lu<`mSy4gj1mHB?CVel0(g_CHp9GDE z@^!)a(#+Km0w(O0Szm08#iuXZ`x=1g8KhWg4tIg+I8-JU2o2E{MU(fv@?CkcXH_Qj z9l;7(#67TA0tkthQbKAfpU{N6%(gM)W*34Cu*`FB$cgFDP5q?Oe;!huS*@G-l6N;= z5BQb_X88U@7}bYXC@3-4imZi0dZzjP4iwT|LW+eeN(RbCN8?#uy4zcl+;MY_u;DI&g`RZgDoWCL*~7nw0bUWv*dk z5kn~)K;S^Afi%4I$GD?!gVum}mFQ>GvokbFf9MAHeor`+xKj;B4igMOzyr#?_j7@% za;pdCcF#9+m(uaXA~hHoGClXro{PuOPCrCvSIb8SV0f)bHh_hq2IG-(3Ka`<3Dr!` zVY#&~mNywrG1QaSHzLMNG{6jpj7LCO;AJKRdxae$t{7)6Yx^h=^TKHtkMr7_WB}<5 z&edv{C{?%HbVZ%&*j6mJZrrit-(F-@Z z$aC^FFY~vsHu|J6C2p+(Bd&z)2-r90^yG>Vxjb%GikBcXA6IPpUUWP*Uv1AafX>oR zdn)*{RqU$&v4x!!YPRp2LztkL zzA^YDVUk2JsJYn>MI{`3sKMDEPl_9opqoL0B-3-z3^A4hfA%9Z)w^7^7_fe%OS4iQ zF{nMq=2emSJ=+*{y`~Yr$>M8vvF59-6~!2+ch(d!$X}QMpec94x9~hGH~vY#({4YG zWFewKO%+A`-yV*y`NkLZOi{YrKm7@7$j^rD<-VFrz_@nr&G2H>pe_8t+`StUr;W-nV*TDo|Je_&#db6RQ4xO%z*3C>Yt3F zyY@~Q7&Tx5)F^w(Ku~Dbr|4m?cs}PBZ0E@7l`$vGBmGr>7 z5`5Yw7o#U&Xe)jIzljmo{`g_gKTh7>sA6L!btd+hS4N4&pb>trXhb%8kQGd!njMlx z5tlEoR1}-tdBn3l<4Jb3C@))I)S6l-Y|^o>WO1)s+E9GiaQ@Eb>QQ3Ls%lZoqb0bGNDvRt~d6*!?nP{~y8iE?v{7^O7?E~G%tL{$} zq*rXv`-n}w-Q#lA*1JH?0@%U6q?kzOq1gbJVjl2IhN-vZP2{JW2Dco#8iNI&JVKX) z@9AlTxbtY1k;P6_)yk8RFL^_(z($9M9Ti>n2h)lyHd?L zoVMvuah573unvMmIgrt#{q=__1uTIk;pic6RIikq z#M$F6S)Tj!b+zXp*#KjUg21C`vusk@=u!y^g&JRSGby|q5f#M+mYMQFq7J`YC>1r| z{{ib0qTRqkjNcQO@E*ZbSo@j_y=!S=u>cR`IcL9Av8>lou-9sm?sVFSH4MPDr)daQ} zkP1O-h;aSrgrg0Nk`%^p9%LVm>K%zBS!tf9S4Yu{(jE5b1OK2E>&{i+E9G9>C!(ST zh@&CID_iUoUEUiR|^6T4Ld(#0}seO+<@n7u^ zU%G3vtelV=*6yVz@4KA~>Q6qik*7|WmfH_a$kA|i)=rGLH)#wBk#U|__enRWXP0_e znkx5@_>e|zb4aH5Hm|5rT+-8iDXxM}@AWb3EVR+!eGXHkLxS;E{}!V*!ac@T-Qr5v z#DUWeZ8v{T)IoJ912Tm7Kssp;NDZh?8#`~6F9 zaR(1DYX9{3zj6mZ3hra|W)l<%z7)RALIl32Vm7MiX!M6(sFAo<-E(>##PbF@4)nno zg}svIy^=u=O>Ev*Ip_JoB-mM9rLzJE5iz%{|7pu(mY4kfqn+0Njva`_=NF&xG*yoU z03FY&E1AW%VOY@271hku^Th!OARh0wW5_B5cOZCn6oEG-SIwh;;BfZ@fJ&gZ@k6ds z=|s;PGWQUh24#rG%4_ZZV7eV19V2#wM`A3RdAVEIflf6{KvMNk ze5;ku*d?Tz5lWP%9dpCUQP(>j^VvMKEkazF{?hB!0K|c}hlTYkFKZC@exxcGakfNr z%#%`O5nmo~m&|(S;I1>}te^CrYx}4H;HVlRpa8;U*4lR!)&p4(v!$F~6H{)`^D;WI zGF6B->v~&)apZhJfBWHQBWI1w$9Z6qMdrILy_v2m=ZK1l0$|$t5R-Fpjz(I+&EB2? zT%dbT^Sz52?>nR-n;X#zd)J~_u7FjWN2}6keN`e_iN}1gZeAIIG95BebJ2$ZQAP69 zDW7{ps$4N|fG|MN>svQSCSjvg|GW_SmV)10^3gpr)ofDGtaoLlNzBaCAGAV9vME3D z(*pzRVYt5_>{29puv)&xIaY}qdCZ0zL8lJg$Eg^l?dVBm#aT<8Po3X+8mSLTJH*6x zfFCb+PXN5C4Ux^~vB3oA-4(0hExg9E;&`kG2GWio04S~p>O+x4^|JVB#+hi0M2Z#K zc*sIL@oo)!IZ)n!Otq0F4b*gWtQi&(M#xcOl92rA}{DZ|(czJiI|x2k!M`E+Jla0;BKHO>=>gR{<~(MH@uXVhv8jKW+$ zQZuzg{_5pxhgh`+c>Ox~?WVPQJ00cg9&Kj`XpGDoskQnIqwNMy!T@_ZdJYKf>g#d= zYpb&mprX45<io1=(zIqh z`YQe#Q97#F>jXoa=^qw(U~hpmv3lV3doCU(?{VBrNBM^OQ{B>xAk_|YbrygN=Z)oJVkut zyL?dP3vO%fPCL3gte*_B9hjH3`(H4C0a?BOMHJoqbR*-}^v5?z!j3Z0H9UOe4!K(GwQe@`=GhP+ zH{_xRrEU}r+|0cs^Mzm5I0wR~IcQMZM!)X>t z%6rj@$kXNXZu1W~w(rFS*TkouLJ*@f2U||JM zauZtPoNt|%J7*gf473$Rbl}L}>K2Af{&nYt{v?xY=b>{g+wP_1V+Jy?bLRz_zxpj; zGW3Am2RsNy_pY)@9%z0UNR+1g^c%P>{?dEJ3bEdWCKpf46iJR{@K|@`%nTJ=4<%{? zVt&K2SqBA21AJ)Up2{pHDsaBMNqj_?Z$9DpQSe;P+oQZC^N#qvL|+X^vJ;FOtm>W) zqQnPzOV$bi)m;yzx*g^fK4rbbuqO-gvRE{3;UFo z#;FNLPw2p4UuTguUZtiRT%$wWt_Hhlzywi7=0C`DmBm64CR>M~_ z2OjF2QQeN?F)Ew>?_o2n`=Mp)cG@Cea$4%HTDMdhfxF5Jn&tI@JARPwhd*EqeK;+; ztP-93WL<7eYe56?U$A_^SJfNO*j&Rec%Olhi34=ealvT*o-fBl;Ya`oN10_zWyii+ zThDZCh((O{;95q~M{;`pD25!Zw#$^Jt82V)07c2Y$G_fhKg;gv5;_{%gCs*Lx$uZ0 z_u9Vt^OOPMqh}SqYg!THCYr6HATt7}A#gWrK-aimXyYSG{LBMmO=yh?(9f`GJZ>zE zlE6j-wxiK!1~24-p*);pqw|Pg==HZK$5`R zEDMQGSgK745m&z%0bc!($tJJTA;jkgp)nfNT_-Gum0+v(~_3#_QLGw{2~K zOn>)kRodzH9SsBV;jrE@G(=dn+NFC{6}~QK<-H7X&A$JY`~&Yx!?mNl~`K8t4WADoErdV zjof!$G{~5|${J1%=L~4b{W>zQ@P{!(k{}4hqSDP_{)QZz4i2<)ppDct890p7^Lh53 z1qMi+mCD?OI$Sp)EQ{F@&e&PQ5g26TSkN;yKufHckfM@hi=fAxT6*gd!lq&5T?mIvK-)*kZg;*o9F=k< znngwMx33jjuhpj=iJ_zFg+yO~LuiQLV)MRpf|K&4&$d|s;8nE!tT_PitM`fg zRZh?QXAm-SA2OVq!lJtD&mg+HS?nXXWM2(5Payqq*#qCJ^y}!D9rt^H)&R1}7&)p0 zK@<=9dST%7EL|GE<%d~g0QJg`!fyMPNgd3Y?Hj+m6yV=d=)ht(7o7z=H^?(9NN z{MHeZc3urw@Q8<1kUEeN5|q4U6oUWZaubC|B#S%^Y_l_U6#93}qvw49@&QJGyAr%| zi9S`1Q+jZW4IHq{AvNVIXok7HT0~=J|T$6r@M#7S&=pA;b zIZ3}zwY?_CCW9r8A6Cibs^vEbGYx0GfHRE0pgF_je7a7i9*k8;h?>3JqKmDdZVUsW z_>VJuu9e6x-M$6PlS6Ryhr>@!HUKR@s*L+BN>tA(a$qb2Z`^PO@~s*rI72wRfP)DO z>MCF#h#}yxPxF>l6NDW7V^bhGP5<|UIrts8&4;dmSzp@#e4tKV)j$|V0ACNG7+Cjl zF^0akl4Jbf@QaBSAYveJRS_%A2z8wf*y82WFz_!l&y?g?_5x9r znwCb*d7RRcF%k=2*;@PW>G$@^HC`Rg;9=Q*^cbApoaPNDYc^Ijv z7XALQ;hSEJ#+H6FTkD?dfgooRv@@Q*P65b7BWy&Enn3tq7R;((D_2FzI)vpyJtgGA zskOtAZm$x;qI(!z)|%ON$w2ynFA4n7F!lW?>eottdEESpw4ep$i6m(oHag-1No~k( zG~E+XXQ3*g28R@g|6HEC8Q3a9P(gG$Q}~8T($o5S~r>$86!A6z6sqx1I|ww`uQJ=V9R8?R-5y$ zncx_J$O8sBFM}x}TPg$w#|Yo82c|8C=N88|Q&G3tEgT!I9PLw{@I4c)6TmE)96LZ2 zbt$}-2Mm^?#~b*VLU=$7f{o8e#rR--^&v7Ze+@kgM`mPz&6YH&?77{1s|@Qo@2!yN z9Yih1UU!h{tM_kIaHPfGyy=ffoKCl%JLD?>Br2Q=^kX2#a68wZf*2~vL^b&~d=uj% z*oD-bGgMTyH5RVC-s{H-iQd{HlVSi0-vrVVj`W?GXyiev>jaCYTrw5a2Gu|Aglmv@ zf(r)V2M)E6<@EIDx0QbWr%56VauB>2k`^2nV*&O`=w7#v_yOq&Ro?)tHMB>;w7V^V z`{{3<27KrO$>K^g5^`^rzx3lPJ}|Yoyo8o1=&2pL)qhX}#RF`5Q}r~o?n(9Esi>sp z3b22l)}XppcTYs)&&T<0D3=QI4Spll7hE7gz{c}<53M=SMZv_S&IUi_r+>KRfBlwH zSkj1A{m0me*nAne00a7v#1twj``~{_LH+ej_9}2yA6kmiLUw#*m-?Tc@?T#~_2JXG ze<8~=1i{{1C4|Bs6Q?@#^p&b?nw{=+i*_g7M%`)?Ng-=F&HoyX^HQE~tG z2mkZ`FFyPKFAse6i{JkL%MN(+xAT90QS`g1j~tTy*Kfo3xaQth^N&<={KEgO-~Ra} zQ3MlImYW3e*7@syt}DQ+D29-R2qjLQpB|rl{rC0FUKhn2MtMA zSCrXBM%o}ba!(IeY6rJp4V)ws$o=>C=CL|E%xJ73e4)4FG?UCPoKpAn6tDh9^VhGA zd8H{W9o#U+wo#@jZ4B>tJ)wPk|N7rwT*k{FTq|*g!{32&V=t?uqLmUHb^di9?m3Br zlI^&=nU~fn?ReyIvK-a7Um}zg$b~_8qKy{jVj5BA_MqKjHi_EKWydbtTp`Plx-L$LGx7IH?%vM%})!@$3DY{PY3V zMiY;01~s#6wt2~PzZiTk+cAtXQxzn~Wt|pr-(idvs(tfX%}7Ul9b?%)q%be$rZw{9 z+u>Zo?_4(>(}R2BcutEDFHYrCH(E}A>n@Uv=qoGMc!{6ImVB@yh%i(0^6_-V@r+&e zoN+V7Z3@;Nh<18UyrV~9?dX<_5bNl2shQ31=Z`UzQYpv?>}m1WDAkw~5r6C>Tm2xr zPA9|JCmkX)S)B&@3+V2J`WBGR1ffW=!0kOa-6zTS?HYD{jitdM|M`Y5aw4E zq?N0OJVgOayQcQmx4nUH$AA5XyIO2H)^-zb^YCn#4ef-PRZSpju;gKp#$1uQL2l%_ ztt6%147r|dGVSm%79yDyX=;j7Dji{^;ihRB2Uq#F=!^yG?~2I$`#JvWOv>-c|EC@> zGQo!gPaH^!QZq1)W%V*EbYabu%IJv=l-raL+^iHVjX$xrx=!HxO~dtKn%ntDDzk4d zW!+*cw<$g5C@g1CS+q#_e6yX{{W^W!(W8?5AaZzC1K%SM+nTa)FSqRAxx+Ur6*${- zhI#~IlFRM%FNE-!YLR*A17;(f#aI7mo+Wqo`>HHH5}RB0R5dgT>!SN53m(hPcO!0S z(M8OuhvvBRZb~#NRyh@KSfiH6>T4NqXi&Tox4_|deYqrV+0$UzJ&u|26<+vLDlF|# zi@CTW-8bRHkfAdD0?w$<)Q@CS|60_{LB<0Az9xC}f8NrI75~pQk@3W+`Ff2AjM%Euvd-T3L37#mru&O-g(3v+X0fv%_5IQn4>2 zNjqs~(bjb|M(k1c=N(o!Wk^?G5`NmLpe!gg@)$MG6KtK`lJZ(TU)HN;+mu#j_F|)~ zMzW6utwx??eKoU5j$Lb+jUA@=TwMp;r(6}A~la$~wi!wjrynBUVP z*9C2cF}NI0KG@8ai&EGizE2Hy)py4lCOcRj$tM5zwYF{43HaBwwzvF0@aZB7KBUib zQ0Arj`RFcVA!4U+uAP<$y>I&pE5?6P>1=MPCYQzXv%LJb$_y1bf7V4yctzK~vJ8zH zwP8;~<4dtl{r-o`rqX3m!5oD9F~MiGe99@iY9hNm3Z5ELq+Dly zGQ}AUOx;)Xr1bZ6hf-*UnPL-hxn866bQ5O5jUG0A&T!z>9NPJ3&*7Cg@`LWxUtEGj>*B7|QtCz}`PtODZ+3LRQChhU;bR9`eOg5u?14YhZtT`eY*ddf%TK`?v~}eg#D^yJMN23*;v`( zGRs~TSOM3ET`n+p2H4q>HFIsXjNHCTwzt0(Q8C)@npeo{ms6^oiS1vDPn1rdEFw}Q zqT)w-4i)ovK4rRjy67|AFVi7HRXFk)3U{d2;{2nYwd2miO&rX3ifbb!s9f%LsT+MQoY35?(mCusVhD%%3b|K83GDXW+p=7H$!^Y1Dba9h z4+?nyV1znaxgNfEYtlt>wZ+P&AG4M)HL1juo4ebali!~mRbi-FQDGQT@x9wKl3~JZ z#<*Ch2UbFDJ{wd7vY%?MwvF+uXTo-46Gz$Xi|0`l+9OY1`F!s;FLbt>@Jxu6EY)JG zv?+yCiC=n2KUjKZXjH8kQu$s5mN`?q=$!WMM22lo;2jPTRehKLf4zA8^LjZ~MEQPc zcRM!$sj-0*!kiJ`3MhuTEh3BW7B#KqWvaba>E+p)ggUP~GvvOL zpIm+RGH00k+jJ6Qqwzvg_Tf#6$6k6TZq=SdZk*)GR=V(+g6mt~a+;m{{WnF__38ii zl4KwLa|;Es{6ClEJ-oWK_kK@1_Y(1sFma+mQpiBQ)0acn+O8#%(pcSXgAzP!#+aIe zj`;13Y8Fr9nI>whRQFfD5Im-H=FRyFbOp9%xNJKrEKdtfm(I z&A7QwIg_YnsNMH&pLkv?+N>{;ZjX5Z=iztGMX!7=ze`C zt8}$-cR6<^vLq+%=kx!T@IDX12g?3i5Pq18#I(wgd06B(QV}W%RK1xRGqh{z^)c?D zxc*!mxQ7VV6~<4ZbzeN-+wyy9OZ(}*1X159HJc4xYP;v(!Lc)w_prNLDQU&C11IpIt23$EMm3SWy#ocnVqyZ|5yE-_RbKow zft96`f^&sgz*m+v%beT6`_>!Iq@O*Tohe<|r=W6}SX)Rq>t1QM`*@Y^g?rAQP*Tp- z;`N=lX@@r1?TCY)cHTRY!j9(GC~n&ZAfRZTF2>G<8n6Es91OVp52IHc>B13y$7J3* zx_GIQY}If>=Nl=bFRE|tLQVT9mHVl-Koq^}8 z?aeyr%ed*MnQm$sni2Are+lh{6*CRMR(h*FWp^4@1WPoPGodl)-+Mt5iZ1|@Ubzu? z<`Mk2NcI)L9-3?_e7lP8UaGRlx(@Dj5RDLSZ!K}rHHV^meGsW5x!td8%y7%b7y$sp zGu*|^*7Jw9$M4hD+_8u{sg@)d(N+P4KMVn>zn#}09oVf*)7o~{w4HtR@`t&N$^``u zkq!&o#o^e5LI5z+F2m9_PALChI*mE%OGMj29p1vgeQ+9sp76nfx zh9o{{sJx4#J)Wrf);`cXU4PyvD#9r^GF2eGA;#o)=!WkCwuL*)qdz3hdpeju{QdZs zwPwJ5z3m_E>+Fd<(b+0)agJ}MoQn<>+z*sg+G4w_1Ef0~mlQCy)>c!eRUXh%hQ0f; z`?m~)ynj*s%T7z6dIZqndFy*xCr*tjoIel&8O=TXHbi`5>DG@7!oah*Vd(2WqRqCn z{{ku#9(=p01Y@?Ev@g+Mwcz!JTci&&#*Z@6jI#O0209n$%UorjFK(Y#L3UD9qc6WD z^s6RJgDiIX*@(EOHA*F4yd)FW>US`4I>Jq_+%?RNyl~G;yLhCqFJoy_zdl0Ag$MF- zWMkRg561;uQ(FA8aIA;#nh$>U*)JSrXI%gp=zc&j@40EjB_35L1o3tQ7ViXuV*9CC{X&d0iD1K9ASbS^cKlnqfGq(<5!2%CMU@>`aBO7c_>95rQ=c5jzNUw?bN zpolV5P^?Rz@fyAP0(#Y>({kb^qjjc&$sF91Qh!$OSJlYLq_bB8!081U6uM@4|Fwwz zJJ0n^7wZ%iHBXoT%l7+G_>no8>-`Njwjur$96lT0$HR}@{(DQ{NA+B6 zl_zIIc4(why82|EgXiQa#DbrGzVh&}vr#o~b^rhoAxDVpUOpI}^W1*Jt&i9!d#J6a z^@py_Rwh*Z*yhK#cihiG4Kfj@JU7<{Y8kd7kN1uF>&7ns4W$7j*}JBM1E=s z_-_^NpKo+TcqZVbreYvm^&fWO{WRno&%D8%6UO7MYx+8et_rT&#K18%{Ft-h`@zEo z<>Ep+JC{_of@f9cNdE!s76)t9iU55ck9SQ+A))77FjMi9b`vgE$p`MxX;Q?h7R$t+Bp+!av_ z+`}^vx(USS%HcB?@{!S!H^I>;cl-3{<#z1@pVG^xdHw70(79jY48FcY+Ouuprc0`< zvv0!{oeb-U_f#*R{gK=TJU~*?UZN%&UBvLxx_niaHuYh2Ymz()4wt3B zs-2V#U{C;}sZ{XDWr4BI#%uFc0St97JMsifB#J4NpIzwM?8n?RO-HZ%8md}shzr@D zX6$slDlK2NGV}{>OSSSXLZZBBjq@GPMeg_(nS2ccosiz8)Wo6MpHjlONg;#s)9>zh zD{7y}eb9^BP=9jHVcmo2nKPvt1@QQaQmQ$HR3MFU!U8piNl@+NM}K(rbLsL6RYd%G zb5rVCXm8s;rf270L;u%JYq`0X*`d z<*zaIdOV;xEpk0-+6yBCU3ClD4cEvP2AUb1oBXd2e0wi9TF>`Z?l)B2F``H?WVU(| z067l_SF)m|2R1efWoJt!e7NToDW}{6k&4~lHlH=7D$d0C{cSG)wyo)3({jM|ODW<> z5Y)1w1A4Z%jwoL|=!{xjDxzFp z-Gd6^*SrvEipZG+=x0#gJ23ab)9=Fjl(xz3%7e=ifWi1F4SqK}@8EDi_h+WwcOVSK zhKj4Vp(W@HC@ho5FYLd zq$rb;M@NfjHMhcI%+(Yh4tsZ51iELdio}MyAF@%_=)>7)L03J8or1+K5+SHxSpi#_a{&(iab$ z`4a$rvfr4ai}UbmeZ}}g8SSgeFe%2bQk`)XUhD@tDmYhtpZgg#K#?kJq{`_Lt`(Nz z?X0nxvm2Lw)M?KL%FU$b^L=}Ctk?I?v~(=U&n`J=Wds{dO!j_oKmE3qKupe;_yg@{ zzHa-jF_RP72akJ{_9SAr#_jj+3CGq4mQSY_J)gOgO2fdy2Kg5*udEg*RM=`N4+CY@ zRP@T<^=9LisZ9vCx^>@(IJV*!W2^g7f-EMux({NlW{6HJAe}%gR4gbDyG)(vmUrX7 zs@nl(y%PiqHA{Rv7LYZ2`*ij%OCds1q0SN$d|)$3Ir_w@f!jLVg<#}9#W)Np6^7#D zbuZofvc3!V%QIM?ennvcmNQSOm(#Z`zbpc@506jFWFfUI*(iA zd2UuF*49k_?bGjK=acwF&r}eZaX{9ZF|e&Ik#Hu3yms6W4!t^BZ{!@d^mQj7Iy`N& zl^ii8)hx)ymq{e|-%t^KElWITYbe%li zF2}j%I-3jvrCgUG~C>Mj*0^wUu z)%01th3$_(P0-=H;ylj@n$3OWBkq8J-sgeyJ8}HZJ;s5r({!M7q}nyr2Cdv)zdK;q zWhE>4s$nUp3OL(G8C@&D>OA$}X)0!5j_Wk;Hh3f|e3l3D=s<2IVa{%U)?p@MWczO+ zvz+Ca-R0MMz$Tcl&Ta5A)8a>OiQB{Fp;wT4gwU+gsF8|00w!f7yjjq9CIR2k_uMU( ziy=otgQl;FZ$WIX6XJp-QN0;Rqd=Zz9Jzp{1`gwj6rz^5y+5@LA^ZHzj=zK4+fQ`j z^<*7rrSL9q{<(A^HTGWt>9!N#ek|aoc4V^j`zL_6esSEN${kpS6 z(xvtu6qdwjZH6}UEYc#q{q-V(F3 zYjgUwHJ9`UN4C@*^l5qf<>>ULFDPGLHw;l(Qh|kz?9^^p-+zi9**mi3k=nfB`J9uw z>P3^QNW9f{=f#d2sdny8HRj;UVTk+`1>;QnOw&ws;$4|C?V2ndpO#;Hc53Id_8xOT@a?AKWKccpwZjGU0tvfg00BFR zL^}c<(Vappb!uhU_F-vl4&Lef>?KAJ+o8+%^zfSze%7F=h1O-V;@wi}%5|URe6{uF zD8Ukt3XtgeH7H?`eALA+eH#tkgB|J|5eHiNtrLnBTQ9y{hfvi%3|11HP#A0_<8 zxz3l316dI&l~5d2Y}K@i-R&Bgd6fh!f!*?3u&Gm60MN8UUR1NV<8?!uyz+!Gc`80K z*9|B8LX3A?LX*E8+-qRs8H4g=MDt1BY>_H?@=0ZKGRy8#U<^>$)GR?U4dmt2)|taN z6l}|LPDk(+607R!1Mt)J8_N)UkCug(Hnb>a)~;RAn5!#FbJ58s)p;3v+-X(_0+Ed< z-df%`;ZyMHdzW<&Uii(Xhh$gHo8EML;CmWZJp7DCW%n{zHAgi{(xbsZlYo0%d50C? zK#51ZM2`klo9TNTaK&BU#YB8ZQ%${@ZFtz1(`MoY`ND9AFQaM!&cC#m3&U4VaW8W2pK&b(qY zaXbmCt+DT?4#)a+eCd_}!qUs$v0H21Z47m$j|)EB+H=djOlMV)PhNh}9hJo?p%vUu z{pnBvczMMYYA&ZnLH<11Co^?dqQ>#faWdDY=Q+W}q~pVH?nkL8$Zk(j-eSd zK`e*n+>eI#rDO*{6$hG}86Kb%DZtTd4OTgibdDV%FWnG-h?Qshx;<2z$*I)pnWt%8 zEY|yVgU5eLGym!`Qc?$o?mc>6hY#6cBMCotl{BZ{x*p5m$<}ajW|7?DHQFa`9fg37 zfa<_9L%fbtv)|6G=fuhRCuxji#4kNM{NlqtSzXG9j9c$|z1>J!4y%)2Yqp`)810Sr_@ z9Y7t?&c)}*O8;f&14LIa>5y&&(K%t$Zo4fdzyDW!HK(dJEvQ9uhN3F!cE z++6uxnKqqL#F%Z8hv5bq?YB&MyLQ4Je=Jbr!`4$G<`~(+Vcue73^#%$Z^6|z3;zjl zKFW$ISirpxyI$DRKi2mi_61#Xh{t_Q>Kb^@6sXa9b_l zXAku5v5a8FYo?!f&K<;M;(&l|L)HStaUmIHpAnk5I@Ct7p+TVG+dIEzMTFF^M{kuo zK~^jVIqls`&Qpjo!E{$Snd1piT|va5nLP&_vq@{Y{0b0xqB*}aje?4!-}<2>?N)k| zYt83Achu2X!>-=v7!z*Y{XQd|zI^g3cfL*bU*W}Hw({ziucabxR^^rf(M5Wod1t zS@9lsC!CK%K=+v8LwwZ8cc7_-nGXuRj{8d_lo6E0%voxH6e-N0CSxRW=bB^RfBogx z#~zMEp8aX>#$Ozzj<1hgv!#KRzjp22U)Ik&J(jC5L)`qO=FR)}v;4~}325}MwVwUf zC(HU@zF`_Q)pxY%a5_vlZOAM`Y2@9wxS*C&X|Kw80=Q~K@K#jD?(it-5rDa;J zxq0yr@{RBi$)1|s(6=&LC2_>w$2qv8HTv}Mnj1|Jf&Tbhva=Dvo05S^Rkyi}7rUdc zNVd*PSWK5p@h^lWSnYD5ONx>>O${S{N4i~#X6H~Q`KiP2rcL?NI@*)eNK6|I#(A(w z)#yOZiB0X|n!tyWq2Z{<>>lmflnhq1uJoLKXl98+d)mQBcdhEx=O*HzR%?POzdP3i z{A}9ZX)MhyMd@$r)=qT~i_8kY`g4-!?=O$8EH$fw&JpD#HS+3IzRP!qsNE5Gefn+7 zAi4)K7Ok&a+#M~mPr+-^MMviqnw`?e*Vm_|n*?|lk>nW;T7DmdFLwuPE(A;uc2+(^ z*7N5Q3uo<73R-prWE!LEBt9-ecfhvzn;RD508c~fdMuhZ8!h2DaYKaXoVznxjL$}Cs zV=cK4*LbIv<|L`vJ*RYpqic2oL$V%dPj`6$caI8)7R^&~QQ=OoT6RLKtdw;US;Xn^ zFJJi$%+vfjI~)rg6%`F?j^$UbUKm~86LpQv1v0Avo#V&~pXl$U_A%lMbb`fnq;Cb= zJ|pn44ovi*LR(w2SV{jCUFeK+HljIiDN+(UoqrTH`pUdal#)@rA{dF8a&GN-5D~&2 znBI|^Q0c{Eb?HrdSv8(Rp-|5|9+x*#^71~jg}%OgpUOHsmD=Yu&{oy%ZiUHWx9KqK z&+C7c%M19kui>xYB8mLsM#=NASP5^M8lJpF{?HMtb7}1EExj0d<@;)oRkN_P8W!kHbm z3}W1}WsF#0S``wF)rPCD`E`YBMxtb8n`>8+i@t-E`J=G~q=?FtFKUa;UcpI`vt2Xq zNKx@mtP%q=WiI_#WJH*1$F-G(2VlG4$^)s4O1jYX(n^OkrlSfi3VRp|d{*B=hNj@tueH*skEqGv!}mS75Gv4CLroq3f0YSIH3y>dhgQLv;UT#~4tD_KvHMJWmNxdE@LNgw(XxBk-Y)0UM=LGg#w1N0U3e>7X}F1PX@X23(?Ruu_M;&hp zFt1_7+j*Ll72q!9l@Z1{*Yg$U7^^I1M)}=0-v&<+dq}yj4!aqJ_@9-~fDgz!tmdD6 z+^%ALuOlB;7PfQFzaTr?b8hRdL!oisgok%O8WK)(3Xm@-ZzBCuVWu@(21Fc!G^eq5 zd-(f13eGAKRDAG5COr9msv&mAVt3MwRNjUqux*%$dZsY}?!oBEabcW}MtH|H*$1N} zM|<+@njU?pkY7R~^)qAn9Mr2q-mI#mTBCfb1AZw(mKMp#T$)uv5*Y{KD3sqQd(>Qd zqRYqKIdCw)k(?rdEza#*f0%%e;MHj$Cmhh#C7p@H>ab=;qTvCTfa*&R3BVqj_s9+I zQXNL;53RiK2@hCw>G#ih*6%epA6-$?VxWjPQ`l6OQM^KydXSS#O zn%M^?c9lGQ|9D(c(CRml`EVTTwg|ZJV=x;1$TmTxxsD%m7S@TPf%$qPiewaPt31@o zG`ik-W2;Nr+lK6|wY_46kyv!?;?%Ka#-FyE|8?jR}}vN>_cKsZ;C9J}pPIx_!cM1MZsNVYGQvA0bGTR&@3(kd_J@#lwg5D7-t zE4L5|N($PQknJavfGg7@Rmy`wpzbMmNt&3X<&%7b4--v)Y$&>4xWr;c@_A$*bVy`A z$_<5@a?k?igf#WLo&dXE8Fig5KPe#z(~iBiN-`0S{XQgG&@A5?aD+P50$T zkG(&(?33iG$I3F1EHbN>QiSPqw9fl&8Swt+%nMdi&g{IrQH=EdJx4;Ui86zAu0>eH zjH^u4N2i7I`aerGF9~0PJU;BQ?Nmso%Aj}7rF9PPrjjkK>YN4KxfIjTZNxf)s@auP zb)hB&0xA!bz3q2< zw&J-?zfwUOo#oIM{QiSpdGjfQ1SBr7-$SUmkx`b-xeRwtr>LUd zgIEcr7m7;A5yFnDqYnc#B2=?bBW6K$24Zc#$)bM-)?wIXuT+I*44N=0b_Rx7r1SrB z4F|i#!1!BR0M;Y>DZ|e{vP&@iasE^aT1Jd&GB3blt&*ZKo$mA>kaXlT*d3 z!oJ3)GDhDYfd#j;Tjnvunf%96Tx#3fr1EHKGS7N|H#?%2k69iC z5Wyt0DV4r!8%tE|pqYu#W00B# zy_bDlvJhAqc70zO;wIAkQ(XDtAI?c7gjQeV)f)fyvrWS<7hsL|*Pw#9J8Kx)wBeDt zC0c&l+b!d)=7X_wDGBqf!BmCBb~ky`%zXFjn$Xm}7Zc0I?K8ZA7d%u085&@wOI15B z&Y!v)yjUu|rLN1qp$3OcHg_KxhI6)7EUT<8^BpEiec&C?8Rgl+XZm`u6e8)ue9>e) zE}B@4qgL%NDeUNH;M;Gc>K!Dcu*&9n(O%XixE0hhoai++QF#v3380YvdYE9{BsXc9#Bh%=9cM*& zR*@?k)R{gKH+$2!rJB?t1^3J+IubT+uVz51nS`scH^5=>W`P6Z=MsFeP*s)gU2irx z>xys-SB+2@`v|)~&M8s;AGGbF+xJq}^g?DkVR`eXAjqqhrkDRSJ|TG8eK5baSXTia z9$bF&JdGZN7VueFreQ;ejvsG^BJOY{J=?M-eV}@EvU-ry7PmPyk_4B`S(NvmU}CA^ zT9GJlM#yh343I5ojYq#LpRxy2dJjDruhu-Yk{nMp*x!@LW_8D$KpW_i;pVL!MI|Iy zaOziD;e0&q9*fPw8Ez@svIy)(-OPl&Si3M=C|wIk${xDe{9}9B>z7&mGbBY(Uk-wC zIwDw*^x;hD_aQvq-o0AlBh;)gGvgv1(nV|M&AdVcBVnc4A(7J0fIpy(TrX-~S}&u( z09(?l!wo+y0LZ5&iU^@xRUIks_aN$CJry0?Y?dl?f$*Y@==V2!_X#fc7Nzd7whVAX z`7sOa-0XUOl)5$(iLI(_jj@kbD7h1Xe?H}Gx%hgs_5=-0(&F)oqA%@1`IF}=TOU(# z?0_pJefHQpRa=(<#`%K={WI@e4A7viFT&YU0&kPyQ6WKF9r}u?SC~Fy2sD+nTC$Z?XILy@umY%)E!(5_M~cAa)rt?u|PbzxTR&!P?zbUCpzf z>F$Jz)Ei+Ge86E#g=Zc$?hQQNnp;gYevkF_TGH_AUonw%GYhaqa26hS9!)Gt#DIn$ zK~Y78+OWf}T(9Y;q?I?R2?4wtsZ%9bq)d|on1L+x3{T#FIGkTzZZs}K&DFbrs}7rg zQchlN2B>+#yOO*xI}tS#t1t;rY@q&k*y`u{XbB^8g{rOP#1byn3+EndE2ABA?zhRG zBRY?OX?)p}4NYUg$7uv0`t;?R3lySc?yL}(yg(tqXnqLl@BgoK6L1r2LEL=K9$4|7 zCUV(8lcJ8_^$u~%o*p8C;azF=VO3+LtrDGTM=>%Z3wlCUgk*5DL9JJZFk&ilF&-l^ zd`M64pNp=Km3wRG6SeP_fbTpX92vB#QBZ(IELA($10Y>4ejj~%Qo$XyYm3a*=TQYdu0Qc7%!=@nZ)MNbo<7!IlUQ{q@YVQeFO@pkx@Sk${0U@jw-5`#fAl~ppmyWV zY}{COw!dM}tqbU_^uDH|9ys%tyX$2*bwx%E>zP>K?do2D5ml2c3mLR+0O!bdHT>N3o{Y1+_h^F;I#r zaK{fv^mSKJnReb25AyeT_KY$ojq{^w`;QQ(zT2{Uk81G6rT)uId^dc`8G(kNc%KFo zf7|i@2);M))>6JQ{x!$P-`|VHq<3bI2OP*ncbIZGD-)xU&n+saZYcqZ_fV)338Rff z!BxVi^4iiWpZ15EOY_=O6U=nYVB^cz*aHQ}89WvfA@&xr-z##Wqd+JnnFjFRqyVnBU4<8=6g>gwvK$=~IDYBUYp z3l3hVUT%60STiCI_q_c{2FL?H?oZr7ayP;?A`?}rjsoVb7by=rsS+;8+n*8eYJNI? z9lKKREKbq-^xe3i?xv+yL!TX(fXZ!M{uvDy`ohJNG!ENXrA3nu%W`nXfG8(Wp9g30 zBD*zC41wFZjHnKrB05V0XvA>dOn;IBU;U7NVdEOjeWz>;m)_4+ji(@xtcxXhD#Q8x z;2Gi~9;3#J9oJr{UQ+HiLs>lhuj{I>9V*ut>6Ej9{$f!6Ci&}JAOT9H0?sE7gG<$ORk`a{h`wT_|uj6rHW;z}Y<>ZUj2uq@K);CP~ z7Mhu`Yjvpx(+XIUO-)iV8Uy7Mi@8cWEfb-P;f#kc56))I_8EN?4I(^R?g4edVB;DQ ztH2@;70%iD6r>ad*wvGe41=dS0I*4ie7(@&4|4HuAVB@Hq2?J^*GC6)Vi>I0EXyQ- zT%IuC5vCbPlj2E(=WdouLszdYy}NYH9dpPOs3R?pE|=?g3Fb~`!iNBDWZVB^1P=>^XqzMp5y{}$q z4>Et1-gAcDIm^dCyTn6#Sl>=jYkt?YYmtEn)ZA~j+8bx+Ntw6zqZ{P6w{*8UDsmUG z6!d;LY;O4nt6j{r zOK9n5h<3#l`Hie#v$H=+JAg4Dcq^9?!B|3|bqD@65b^#*X#d<_1o2R+bL&80T)fOq zZOfqgOnKac`>A<%?l7?A`1~{` z6M%em%UPxpzzRl|i!HeYX@^jurv{VNEJ0>+U5-2s%^^XU<$sM$=#R?jV-*4P<}>}8 zl&0$yk>t4w$Z|3*-@Bf-p_V~YI^bmo^)orp;#Ha|*=*jFl0WJTuEl$NPwU(x+Smt~6LQ*bBn0EOT8_VXTu>QK^ zadwhW-+|ioGD>7~y4=q$6|aoO;o-XgueUyX_8eGfFh(w^w2+yG~1c|R7*XL+|OdUu1>x2`2*-c46D zb6q^abm8}96Y%5BuMs?t4CYz$^=sytWKd4BAb+>&Xxp4lYQs9-hfWErmUJ*z%N>DmRT54+9C#W1CY?~t^KWT(H0p?O!GuBnzy{g_=N%wIfS}Q}pmelZ;4}a6*3oJ)HI-!O-&~fyeS9 z@YTUskQh#97*=*wPaQjgUKMIAR^`aQjU|k5(GewhE#LV6JK+09YT(#>t5xta%y@z= zsV;iS!qJ8w1d}3GjnDyXxzWQ>80BtAY;M|7HG2P^N>y~0qQp6A_fBt+UeU0t?^HB~ zkPA0p;ez>v1h9d~WOf_&#c2twRsL9-0r?P(F1VNzqH5+#+bUUFQNlO*(5EMwy^k)#2W=&h{R~ zYBShnFY+4m$+|FlX#5W0=2+H){6@H|BMAu3!LI`ca~=34t#rmq(=q`04j}>?oY`?V zQIUCQjEaVT@Z_sV#oMNVH4VS{m%VwvRTA2?G->#=By*8bgw!k+GDE^Vfe&rGxvSmD z{jJs2vuC~A3*KV+rVnm~()D*wHXw**OeMud8k6N)!TL=Ub_%>-6SkzTw5bEi4fVFR zC(G1sa9XbNCvp?#X=5JRuCBbS06#w_2&I)LgovppcZaTnD4Vs@7hzxNj`s?{x`(jd z!5CR90Pim{LG1xvggOf%2dHO=Nqt3tbZfHR9;;1yd9Co3<$XYE0+`t+7@K_F0Zu;0 zu5Y-Yho~hxBR&&q3+<=OxM$$>m*?20|81HV$j7Co6~Wa^>50m(th7KE-KAl=B;2Pl z5cb3TKyq;~%?`wOvV_xdf(Z+KueDcO!);d+9DPzUSKIDg#pq%HBekxbgNHF>FecZl zgpZO*VGHksUM<}ID&EMRjjbR97>3HmT$!unJcb6F21B?fd3HaVsS-Z(DHATa><_~L zlIQjI#>n;|vh4;wn>fK_~!m`K?H&8}!#C=2&0To$z zZ=!Q%6?N$DdZ>64vuXMvkS@J|nQvcQGX5aiDDrOw3A7mhS11nF{I_{~JpkyqY=3a9 z=12IMfowmObUO3k9tF1#7zhh8hw!e~8qkMA8lTiHg7ja;kaH>Nq92~UKMc6%xSfjw zMy-nZEWf;=vA&EMnt`)J;Q@UnFW2jVMb|DK^l0kZ-b<#XN1hx^o|wKB)+%vZq|{ZL zxrYZs0_@Ip5e7As21ZnY^%70V&SxsoVPwd6xJ#N%I8lFp1CO0-8oDEMkQI5z5`a|< ze04N^b@|?S4{4Qn>#iK#r)dX?k`RzhW<^h@4e>gA*!ONHjqM0|8@N#`AnaVJBJh1@ zh1m-(Wx(ePJMePv0{p>GaTV3C15b)qtAh)qUphi;>Tf-d~T%1^T zpxxo1gI0^Gz^{tfLGY)t;pupnNq&NnZzYgL@<9}KNyWHdzu?`Db=)IhE-JA)%mF*~ z9kx^*)CR&o7~X|Hs&!CSc^L@Giz^MPI7=W=XRwQ^1%lPFM4Bgf_I3zJOPt%|a+YVi z(j~;K;p&f(#uv~B;^S82tH{i4E^5t)rZf$Jk$;z%wHqg9*g9iv|^8u!VikP!X ziW`}b8Bml_M~Xz=Ak(i*F%nLLV)RDll>PasJqoVLK)Tc)hVxCAqDn|JBPW=010I8O zrS;SH!uDtDgj1m2G~hd2zFB>8OamFnp)@o&j64DP&98z5m7>5)2m?qKc>RuwCPF;b z4b?-eVwW-oufYLN`uG7=Tas^wWEzLOH82bFG^)_H^K{zt!eRCTf~pa$2^s7Q_Z59z z+9BHFzf~-m+1YBc8a*#bB-rue$0PiALx2P);@YO^g+*U-12sTSJSAEeNDltN4B=w# z-j(Lt4qhF#>u-lZbsGvP`WQfWL$hSb+^?1^VzxL-AP9>YgK_~47W`9n$V~5)fSDkj z)pA?1Efvtzx@t{}!23wd>WA+XD#bcMJT$A_EbvuLS2ZeZ#AuI774p>GLHp-Ou;yB% z#i^kv%6L3gHKely%23WCK9i{ww6r35Yc~$pC`LG(djjd+8JoV&0D!`*W_lK=a1(Xa zz^$IF-1a!+_xqWKPG z_t(b6#IPb{6gNu^oN^CG`H?t9WB`B(FH0)iECHE*3X$CmLkhrP`V7&0Om8oB3pE+k z8>m`c976<4#>bVgN_s#0b}Vx(xNK1D(cke}9e=sPiatbWZxFn^)_r!jDqo#1ZXDA&mGlIENS0#4Ilbm-(NmvFEr__O zL@YKOtMfyl%vGWm8-S?f)!SG$}j&_9O%TiSrS;C zTMb|(9v?4nP*=)zNljoQ(8Plw-W{uC@+26zB9`v^?se37 zxyAF`Trf>mkbVQm1PjHjI`PbEvwNhDwsn+_hk@#Y?(R_VX21$$3>m*@=#YcX=J2HF zs;v`DF8Zub4oUy-b`-GEY#W_aSh!F5Z}Rez^}>i*TppdR^z`7Gr&wR&8dO>HhFd@o z(aw9mlzHV2U~3N?)UDfrw^-&U%+mzn))+l)GPqMq)%cryMJ&7b8H%)0wM!?I^9|by z9RS43N2$qEX$rvfi;9XUqQpeo5bFRa{&a`#Mu=*&&?~$r!Ech|*ZL-T5^thFK@Ro9 zIsw;_$>=S~RRiUb2|?duYN$1^oqI!p}QOUk+guI-=mH5fUJg%R)KtCHiOk}9cGq3 z;I(#llIIzTI|#)vs`}a#6*Oydb=H;!72i%UYeHF%cgepqjAU1Y3?zS7DF}xO+~QD? za`;4AYP$a*sGJ+lFPry}YUfaFT#+OgDZW}iY)zF{erJF=9F^#gpNT|ub10sY4&6@mpoc*C=dvj73Puu&!s z2{n6wK&wAMeTH%(1=WrAN0g7=-J^Q=zdIx!&SwqlAV*C8#l#-dIy*bv432oLJwi*m z9apr-G;>RB!bIjZ6F`ZHGl~jpyIF&Tnhg-El|=}@;PFg(#y|#}0vyhofCOD6D~n&n z=6eVi^?TqzUrqzFdDR+puOtP%2D&Jdgm=jN zsMV)#Jt-=&u~`uZA#ma3dZEX2@WnUgoaTCdTMSdyH<=zi$tzfC4XI@GfAuik9|5YC z+A3kb1SR6tjG3aCmY7+*1(J3fz70=psM-qhTr$%96I5LgfBV^vWG_3w{$%Z6OI2^}GtixAQDQgq zDn}r(RDBRKf&h!ex1l)(9aBm;4Dg>Kk&7OvN=`M<7CY^dpSrkU zw|Vh*4h~8dmKiKJ^m2sFU_nKl#k8r-V72@dLHC?;PMxK&p zy70l(*Jj`O-?ub3KSU0?1R4b1GJ)=Aj+9OYb;v;RbA{bC0hPyL(VZnTplKn4jr$5m zOas!1FsS~gq+E;2j(*^L{Xn(q#)Tzvr>TZO&@mV!fVvxJ%E5bSXnpvHzGl#ipukye z#pRPom#X+}6(VC0diDE(BCu;erbzbfgek60)CIJsPPX1+rruq=Eq zq_+uNu$z2m(9U^?WK!GE8w7u0dlOQ<~fRGOAl3A;={T@Az~ zVq+qmRJ$MQGJ+az{0UtV%xmyIn!yAs7Sjxs;TiB~Qvk>is|FFF%p}O6c18wbqKP%Q z9uXdNAvO-LoP@d()veP;_K^=>yGWlq?ClA0M4(H;^Mwe|A-F=Dmxn?JG%UpGazn#$ zNTY;!5=3|N9j({@Iizz^NB@jsQ6KjKdL6k>L&M72Iz9m!-XH%Q!+Ldfbsx=a@I5W% zs{|>|KI*62>TRvx?gIUOKpnCdI+|98bi8Y~02aQhY~{C0muV#v>u7M9ty&!(6w)J$ ztgMC5BOS96E3x?oZZjbVyiilW0|e%`(pO*D0;M|9L~p0Ond#1PXz;Q{3is^*NPAFE zYlWm7P%`MoIq>CO;d;7ixLTN=yqV}{m1w_XBae+d@QHn-T3u*9A*tNsM8G4^cc>Bi zX`Nsi5VwND^moS4a2(g0$I7+e+pYt82&U+l#?f^{RlyF`1tWhg;M4fMr_QB#o-jAB zKQp|>S`}>R7;whi9JG4vg*w^V3LNi)9$8P;pyY{N>Gz0`43Eq%amzQf@)( z041V}Kqy!?+fsZU==Oj{wE;O+3tZzNynGp>SyE!j*UH?8s;D4?7SJTn4_xq@S?g0e7^zVP2|Gr7m$3Gs?_&gQ<{dy_v$!#Zc=%U7 z@VX8Ee&1h53owmS-7gQxGMP-f^XGG$uG=P>E;*`1&XuZJ0tv5NEMWS)zOiOzxF)Qn zrRCZgjTa>)9c^hkIw7;YwMzp)Ly8Pd@@#v2aJ!E8JvqUR>zsCjhibPr$aZi4^cf3l zdOJJskByBb2QcBYfA@Ph#(pW~74NLS8r=KhZ2#3J<&YLmz9;(nL0%z{`H!_4{qSCq<%#F{%EgVlG?frn>x1#v~@?8aaI1)w?d>!ouU5b zRPMdoGJ?;->I^*2<9p7S{)G?!KC2W}3mQOQU!P@CS=ph?uEzbuJyz^*K6}Nd!bi-clKW_)_{NS^-`E(ZW=zIJ>?_~aT%m3F8IBV>-Ffx*EXiz!C|0$3tDF6(m zDD99(C}`Tq5~HepXaOfC-w!u=7d=qQef8=^GpWbBy`3%&0kmGRto2=c+5D8!%o*R~ zK(44-PIs}p;FfU|6*;v_ICnog`v>Lnjo|8p#kV@zK0|0#(ClG`0quY~7y9(J58)gL z^q}!MV*T_SX?P0a;N?OyF{s&y-sFQzO`hb)4H&Kya$S9dKSRYAA(?FhWL;PV@9o^n z$wnrZn5pY^BASzm_JKMt>kdlm3rCzCfPQ8lNaEkAU2JsOyYCbb{U0dguUe zBjhMfQ&!||vS?6tg`b(2o11%B6cI|fSrhP36+QDV*$6jKT|LBKmRSMU3qlfI1riRL zj5m0umS%WeA-hW+>do9bZ}-_!{Bd|g;kUL!v2C$xS_Z+#7L@wMA~T)z2Xyoxx4q? zh^M2Cso;iM5#PU7KioM%LPZ8IXALr}nv`p)xbZm|T${vA!1k_81&Z&iMCc4H0)C{4 zZwiA+V^(wOg52Ct&)Xhn0%cEQi+H8&S4+cXj!%Ae(Ao0AL_=TNsvu)euA61Ek>1k2 zt^3>hK_LoShRW3s#TVp!Mc?=R`%Pcoqa8}M97%Av00;WBrI%*X7R$O%Fx@dmy9Sk4 z`c9`EtmzVXnU@$nN}V}x-@H53b&%3p2jBnw2tPW^DSCy0)~b{|%q`~LdZ^>(PGGrP0YkGf6+-2J*`!o- z*DP6#tQB_MGaTcZ=v+ECYtPy4<|Zp^RpQaVKuJm(^Vg3e)&*S%v6h3aSb%1oR9b{8 zCS+tXo*Ga+dLQWI-aWFhwG8n%JoAa0*~p6$8Ec6~kn-2d*n>$p~y zJ3zAM_kEt^7`_ejwJ!2Y>NyIPJ+}WZ@!fDJdKj#ysuq*o2Xe+V72_AloEJ#;}F&t(2PvD z>aCOay`iLUCQIrOg&LYS5?9h*!c1uGwQ54$l_1>GbY;^xa^RAe)|4hQ4hKjZ6$Lcb zC6XW9I&YvGBpBn%qSx5;WjAvgu4V#Wxz*=re&5+ab1>9SyYT$UH;{w%J_N>&M z_xw^!r10d1RZ1tyEK9^owv4_7%1E|nP@642rC>5$C$vqVez6*cH}E=px(GA1@ZUEp zRYkc({6JI|HfveZA0%cHz)n~Whxsv`07kUP;-wXx$Yhrt2HrU-Ljs}g&|9b^4wG~k}~E-3H;!ZN@k78K9^A|Qyyx?2MB zf?TXYT?s-HPtq48miEQssuImo@(~TNfSUO^Is&%tCfO}HT4qUq%yG6Q##mb)_{jmN!b(m?@+oVa~Mg% zy49I)%0L8B_p2b7Cj=}C-jm*)rP(}*Ao&)!<2SbP;RV)f`86)Vhj5NX!PB4-5|>UoTGF+Yq~GX=P=#&DuJ@s-)!l zMjCSEFWc_(d^7zUVyoP}q3=3LN;9_P>bi!42=gJKpdcMI@TACK+PfRrj_d~Ctm24( z1|4k>JgcHX5%zLjlbivlBDE;EQ^x!h;y&~niQrlEMDiLv`+ZE(pe*2%-n{+CkPyHA zO7#}l@Vo%JKR3b&#wT7!?tx3^YL9nUR!($f8}8BDo(UwMX4rH}>T`R4bNdsxR_ad~ zN(!{@c91H;)=dm#V{=Z_1ZRfq*D|Y50$p=K>jIFN1qFLuGDuOOw0~x=zTnXCu^({Q zyT1bRpV8?dUlO?Rok=J7*@mNSg3W2*RiJ)Bl$=zKnoUt-!U}AoG6Cgudovvo!|q!c z%ZHH1kdP%BfmP5@ZR2rhU};V}hP^s$@G&~0U8&!bb0lM|j;VYWMt-LZL%+(^KX|r3 zeOs8EpI29>s}oW=F^Cmb2EggdS+RCz-92sHt*+=pjU0cvHinWo5ReZwc6sQI`b)!H z5ildLCiTpWqH*OC?-~2SXHNFEX%P#owKIehSc`2o)_IO-bhZ;&lywBW?hS@s-k`2f zH=Lpxr>UnW7EOx0pTeDbHvQ-xuy2`}m~;S{2f`}Sd7ZybA6MMLaF_sEkVY2F;kcL^ z1W=Vf1K-x#Qgd{*rc!6M?ZOSKr438MPVh~@&Dr6`{D30`^=VnqpTzh0lo!KLz!>2D zK%UD%Y6l~gdsmL31x*A58VWzgG1CzW$nk`)Q2kkzz;8l zsc9b?Vk0p8K2Oi(xxI{rg?0nZ^G*vhX!QJR*{O=S<>86o##_ine4ZB@9Wxe(LRtSR{Lyu)dQEw2t}BIY<3^V z#C~kLGoj@rQDy}-9CLKLv%&ma^wO=S3+K;g!p239wJl%<{Wfi@vbAQo6>h@oql0>$ zs?g=Z){4yXo0KGA-BQ7Y|AdPk?gr!V^G0K2(1*j}5o$Q8@K8Vhd;9o-T}TO}wmTxs zaPh3ga!ct zE~n~du+v%5r1!noV5s<&rLQNeTNqYt8DWSIA~U1wEECM@7P78va~v0$A~H6rB$-$W z11spQdr{J>6)q|0Ag=2OrZEg>`;D_>C`BE&)a`&>kkm#G80{dnlnsQ=Z?ZWt7wGl- z@cF2j!zWNil4SkG`zoF=K^5wpamrlw2wh%gC=`n%Y(0qcV0Dcel^1Y}Q{Kb)W*9Lj zLuN8W&R#*kmUQt@_`d7q67O3)3xck?v*>kR?F6AYgG8i=_-OqgO4d4;H01a)mHUqW zE_}E)xqL{O=rn5=RXwtiWh9EeMs1ku&)7kBl6f!@A&qplr?%63u&Mhgw$PwQUbCbX zCcU92QVMh$JL;OzF|{qa8Gg&{2CmH-6*5g%9-HVeFkT}s`7nCuvV-G;#DVaaVHs^L zHXLkaaHe#)zBrp4A2V9Kwxw6Mesl)fXju)XVFR1^;~icB#WwMznoHu z9M9G@;%nCC3XcR$FApltYg=wWO8y+!EdVT znItJNf|cCIe_N`H#J8a8m+La2l#XGuE6q}G)svWLmQkq{tlall@DKfIDS5dy%QKh* z0Y^*laA5R5J}2rb{9L^l(f_fmlefH3symVFmnfbLYCswhYB112@0B0#!QO8feIO{|Ua{F01XOcnFb>kTYj+o;brrIGF7 zxM1Mi(byxiXs)s&q#ndtN7YiWsILW6U>}mrI0&ao9|LoAsUcJFw)M%=OVXN>;zF%~ z=I)4q;v(Ss-Mh|Axf3_}_4)ojmbD3$!BmN^n;Y_*#Ws8|FxEA;SB$)j>=&2Xf~q-e zN}Q)QE@_rr4kVIm|9+!z=BJ;Iy8XbNCXI|EnH-(u(qgI}eu>e@1L?k7Uegu(%Oabw zB1SjE^ZmyHHlefev~^6_8Q4+`Rbr{TR(3WizDJ>E;OF7g1|YfB%z8 zDfA$us9^IXMKXh5%l=rw8@Hyk35;dW&iFz9lW;~P;n5kK_E_S9Ln_#Jnh|q6B0I%i z^X*p3igymikVi#nef7`T2HNA8B?e1+CHY;U!fbTzdv1e)YB0ayZ;L!)VAT1)4+vhJ{ypN$QJamv2YVVwhn$XW@ zKSpIfq~oJ0Y-POYy#nX01a)6ke|}Gt-nvIc4!y^tXA3fB=~^-|y^-e<8K@Nf7~ zAA><8T-o{JC*Kb5Mxs;{h^B;yh^)d0C@?u) zt{e9svV_qUK>^nH&)gD^ZeolQnh8*BdFE$lyHqCN->i*glc~6*C@Fs=I-ENrH${AS z_<+DjY9T>vNv4(}ubgvjD$&E^hWMu1253Jc1r?oj-5Y2+*vMU*=&%&$aD9veKH$r}d}uAb zFUGQ<_1}l(HZ<}gL4G@iB6R!u5%u#Qwb(g56ba|HqUaYGGG_$WXk5uVnNaAu9JxA3 z;EcO}6Ou9Psu>$|Fvz<=d7K`IgT3BI`Gi15j9crSzKF?~Uxkxenl0buOP+swN0>6Q z2~GFUvR$!5kTO$>xZ+IZR4Gbw-ia*y#W1p43)5jLIN)0kLolYNHcfto4O^3foZ3cy z35XVu6PO{r?x88`-ch)vr*;~Pcb#l=2xH#tyT+n#J++?-mrU1<`l60!Hr4z}x1zAw zcg7={VkexK?JCEF{z_|+%Fi)9R@c+GUE@Ievo+jwFv6KZNC()>O)j&sORWk4Y#0jF z#bZcYPLOf}cpqyPv}YT+9y!^o*ZEQKLtD)oOa3wwt+KH;aD3MQSxT^#gp|QVkp*;G z>!t!~xh(@htmJ>;5SB`0Q~rRcHz2%*zue!4#V8Z*hLI$wYPuL19jJ;)uxq>4bLB)i?Mw*pO&G@Lp zxoc5jp;U&VVttLTUdwsW%}!v-Q8H#sDV-|#<(CJ%uKie2Kl4(xC5KMVbZqwLhiXKg z&}!g&3|ITtjkn$D^KEJ*?~8UT^#u#iG*l~33rbql0~%87Ax;dzlVJVm>_G}QQq}py z?1xh`kr5qTXLjFgN%}DIEa$df0oQD%zSE|#D-5t~!=QXB46KYYl`CtuuM096k9unqS27TqYB#iCT3hplYM~ zF(FAJde&8>a|ypZ#FRgk2cV5s5oICUbDfJD(%BG?hgYkKLZ>>8q-A0*y9fhhbp{n2 zjUOSCE;^W{lzeFI9K;0_#^`EUL~CzNiCag7d7QR~-jJ!kRSq0YqjgKteR52}kjvs_ zu4seaz~MA!Tm*k8in~Q#p5nP`d~t&NRfLAtKt;`R*09sXi(O-Hn2uqCDK1U7-8;?o z9EWAIbyFoa2C;ziiFrv=a#RS9msf~+s$rnEu@4I&y-4S@GC-v%bE{eUPp!_4bsP~1 z6S)juQNQ~v#?KKuIcY04RKhPS$0yW3DkF)M@!8*QsTTe-TVMD@lJR`voKq?>Q`*wV zQ-O@V>lPrQ-Ac%ZIg;hZ+H72I+b$dOTp-4g(=H?!U&$(p09ON2sPpIxE^p8(;mem6FF@;7J$gbbxk^4_5!$}S---B2|< z^^M-(^|wC>>;Wew!+vi4^1HO1r1_OT|G4kWz0aBZIhNE3rHw1ZtU!m|V$4&*;0eyh z3QND_k=(kfs<|+8^O636BtegNmYKO<#Z*8YXWk)FlBJH#gw8RjFJ7i`NH&t@c}!ta zGQT>smB0+J3g1>z%f8_;#Spii)>xPBf9-7$L^2StR)7&!cQku@&G@v~;RQyKr8wbh zhH(lRLcu0q)w5KJm&obR#(`@^H{xq8;k-PiTZYvTh-Wevr+Z$%f`@niuYcF>LDcvQ}Xp9RsEIU9n)_$ z?1cjYhi)Uaz`@Si&iUCDmtij4({>fjXOlGaE}>j?nTHdN1V1I^j?G-JG78(CMRbgI zOd93K655gbe>7_sQl>>u&KY6ggzQDXp`6e+NbEZXO)*&0RM6$BZh_E<`>iPJ0Jt>N zu-D~UmO+?Bn&yl+fvyw&od2>U?5OW`R)fA@C|SUy^4@iB zPEvK2w!A(7`qP|^(OgbBKz7{$iCn-%>AkcJ6*_XaEOa*XD`iIgdfOZc~gkYih9#D=PgB;e{$PKMePTJ42jF zfXkr7vf=IqzR)+J7rcK}j8H&4R(AB}oAL*})Hl2QuM2wBsw?q8A(SgwpHC`2<9`=< zl`7(|9faPzHqDv7A6Jnxv9nw(sRXF-LygUsdF%=SYnB6Kduomx9vwMK3#AGkx6O#Erw zb?H`g(jI=_k!HmPpV0ou(IAse3>|QdyoF{Zt%*ON$-#3g9*TR424t_~gzUWxP9FM# z+)TpqN6R#YGrgeWO_7oi>p@rCW>!hQA;EHYtdI}~1GBfb6L?^jjArf`~$+S=jEK6J|Sp&_ZIZO7&&eqOE zeeI4wQCkDnv}~MYsGq)s^P6CZvKGX2qeKq1S*hb7T@0s2UMd}clod^;Z)#S8&?6}q zc+?WgOtvEQuf>-|mrwNAo)(pN!1e|flS*|JJ5WU9t6ZdClw+2V*-{5ART48F%zH25 z+yzrEBzc|v-^sC{``ng%zeW+!<^taL&?w+!1=9einW~I{`$#W_&}P0+NHtcW95GRV zL1avW3%R<3;tVIwJaw%s-QKFUmGKUa1i#-UILQq%#?D4#B6D^%C{_2XLfYq(Z_lm} zqm<2n(D0A?@U-y=T;_!#A92<;niE72(`=J^bel(F&UmyxwPQ=R0pc*lsXIu&U}9q8 z5B-F-EWWO;i=h>f8e6KjYm>8Z!J`SAy!T~bEPgoCw}$Si?fzyuWOj(r-R%h@976oT zJnz8-!- zUWYWeib6cr7yl~gNk1MNfFH}5SP4Dn4y8rIvB1fwSq5B^z+p@zldX3g7DWg(mG?LT=%sM~{%|am!2 z%mFHBThAtFl{ED^aS!dS9wK~6HEJ$cvwofu<9YDX-;alnx1icrr^${1V%77j$O-rs zr9^3@Q~Gn&{qqx3c*J2|T!unLjQdB7Ppm~CXLJ%Hzx^$6&i28|afO8o;2Var^y4%l zzi=?Yx}3#@bCq~ZNZ#IiU~b1#Yf)6+&*T1C2F1Ty>@Bsx`D8s+@%c!qJc>|>w~ytTHE*Q(b9?e!p;Zq4 z)FP?NpEIm}#LK$dOS_$)8!i-%gJM610-?~CT^ZIu2EhOX$`G?0mR-**)6Z!+3YfZT zmiy^qCz0`!PZx|LzE@d)_T8YiG^M2$;ctPV82hz)>fL#kXwZE}?J%S*Nw%r|l@NO2 z4VKb7C0VSsTkEC#Sm44@4?)YZkv9c6CDPI$2S6wPd!5QkZY}*c82#NDex_Sb)x&*9 z8mOuaS&EsfgBl3Qmv&+HWcZ&uUW&};Fxgm^t9}#k>fH^H5ws2&Xs-RK5IQ_}J+U5= z%Yp{moC=wn>p+)+hy+OuG$=o%{-M!4_=I!Z>ExxGOl zbtDl*wrFWh|P$U;Z%Q_wOod9j85=%lkSVq??~cGjCR zLOu#XQq-gHF8|wAE6dBaHrrR#JwM}jEcnGy`W3%8dd>wAe@DIW45DDFsHs!Kz_|+( z(;hh9^QstALjz#j{bW#D@0*3lfmB;IgrUG6q(XEO}{dgK6C~TN9-(?Y`LEmFtS`yljwv^(1m1hKvo?J|42CE{rYq3Ex>c zTf*SudpsA9zzXKxJ?EhgJOw? za6ziIvtg{Z5?4K+s=-Go-)K8_R+biD-pnlo(iNEDh#ipUqpM`BicmWj67_d2$ZNKe z5)-yQ)NbbfZFglHf!5mop7O#TUgw`)f)!z5$ zA$DG#hH;{1*3jDTCBs77$G}SWg(ey@4nXN2Z9wnotD9_lDd37B@7(1?um>tx`hB zEW1|rtNc2hV&H9HO?`gTPgK$DM+M>!0^8iM#1hC5`P4})NoU~(Us;+Zs6Kt-a327l zg1%5$gCzUZVJ~|)5jo>5!- z^Grm%Y5_5|UL^v~8|9&C9sv%WwXHaIzK&EA}E)&+viU)hiyt5 z=50VixHsFH3aOaWin3zXwp3J|EVkpB#NZ2iICR3fA%kQ3d}XHJJrIDXwg7zW20}o9 z>HrV`*@dr8(9MuBLcFrk3E%=OlNFr;aBCA%y?HFz*4;a z;tL49dG(#C+b8gFBj`DJ-J3V6AHpwj(ngY#>0jT!gXH;NtKMnGx z6}F}_+?I#oun{1R3;2h+#+a_R;*>S{Cr z>vcYPgq~@CZwJ-TWGa1+Ky+@H+j`o%k2j~qkwUoIme9H`z+cN{p18X$ovF7bLua~n zBlX*B&N-;{=!&(LF2V-t8+Jl00k&?a`3)x@-@wnRtL7%eM5d}{89b*u(eAY5xx7V} zFL}gIF`=MDFolVQ(CgO<$>DKvJQ`im%FY;J`rzYw-k1f*i$PQcYR#=<3X}^s$J$FB zM!3c7p0|X-a_R46=&D{x#~TaN4V#b(^;ed}(Iw(l*^P;A5;aP>9{Q}z$Tou|!L0z9 zZt~+}8@KxbAuW_GTV|`J-rwR0V$I@v#*%k7d*txWQexC68qfNHgwZ~0DWx*E0;h30Eg!s?dI1mw^X$o1> zyh=-aO_>-5s@8iTL{N_4vm1;<&HxKoUoPD3eCVsNRFGNTu~h0AJ#OGnLMMkX6P2x& z>mlNS&y1Kl!xRYL+4vk1`}kdBk+Gpe5oiki!I3?lL~JN*KREL;)JtlkH|LKQVYKMGf#oX0<{#Np zAxN;-eLB2mrsw#0HB_)jqN7WM*W7&hMwSolmR{){5c;Sokg&!GO+9*Fg$D+#iY zjx_>1dB*`SGT9L_C(rAW+brjY6U-!cl;pbQCE(j2H|$LyjMBbK!&)4G{HVDHw0W1{g^Y6vCnRb5BQVUQ=nX|WvusriuH-ka6b96y>Tx_~t>_+y2L%Ko!V@lr z(P?y9uwynYeO=UF73 z9w>zK0rIo3U*>*;yz;4D8m}4212YJw``Pam7wRZs+K$x9q@oL#EbdQW6xqR?UC#ly z-cJu8FHM|rb@%$2ll07y(n?`b=mxIgASS6DZ?!)UISJUIt-PA=sZj*uI#xo2Pfunh z%&{>eD$*ECx?dE+wv3zK-b%QKfT#ZW4^J;%)P#Hz(B|rkekn|!NtUC?gq7P=Yt^!r z?~#xyRSd)1&Ovxa#zH%Lb|JYm`e^Jlc?RkVm}SHgPv;gF=jFiNZ|9Mb7hXE{7%d~t za}QBun}@<bLWQRp56&9(j&#t~#glT@La?F-quS~_WSHCl@svER=&i768| zDMs`9Vx}6PvcJ3}Eg5&LI0&Zml5ATsXXyU@Eu3Tse*)^U=$@d5=Ue^ypP%~9DT>%E zX%vB)P7+b|eN}j2OIkTZW!bFs4%UaZ;(?;%AD7n01TJ(tJ9PLm5pc%Yc=oPN4+Z)b zArtr>1ie70F;yV|s%@L_c=zNg1S64(N3=>h3?f5(Sn1oRAWy1;T=cxGA^6aAIqh-Z zmFtvkB<;&QGAIf^i09%=IrS7$(cx5^u6?ei8}#)5IwW7twUa-@0)ZND5eUNo3ikXb zH6l~OXYO-vG^bdy2!pB25==9n#=7f)Zr>%YHyye2?V~ zQ1EHRdV^PLn`OOHgRQBX`mtcD4p2OQA~JdDf|Re1$dZ{f)8~Dn^B23K$1gP}C@qLs zGGnH1g?X|cSc6(EalGX9DntC$4Z83{WYz~Icm++j&$ois)33i?sdt~Hvn(TeBo_&z zh8hjE-1t61I3|~VOAs=Bj_jrg{jpd5nD%W0(x4i;Ut_bH9n8ht=-Ic5H9jLz%e@#a zy>-9ZzhAho3NeyD*%QNzw2@-vBP5(wp(MK$HYmNDCL_mswqbNSdcODO&ctk(dJsa@ zi+KE6EhP$A=oW36c;?{Wc2-q-PAyt0rANs^Ei4SLmTs*w8vEUG;RPE-^Gq1XZ>b8U zeif9OqKo=Eb;G?w>OKRHA=##OgpO(}B?q3$*3>8j@i(H?ikL@nK)KpZQ>IuZ`a@9i zy%;trbo-#{;Xr6KYdiq03c&Q6ckOexd zpN(Ud5S+3vUn!a4PuhP|q@kY=l6ZS*qw~vp4{L-p)s(S!#LpsnS?ED4-VE8R2O+!U zhhI6VJ9z!a3g#x3526Vx#k})p7V(~$`X4?HjFuDmdfN?}Ka2|}KV747bmL0&oUfUv z+E$<$@v+~T6SWUt)Hj15*^-AuDy3b-Ke#5oI+tG=T$Ba@7nKyznPhlse5Ic4O4hSS z=^aUe?gOSOcku*4F`M6_205sRwxk04S8A=S;J2h>MQ58Sp{L!2XI}wKo;%27(an5!=>0r%c98_s)AEk@RfTPy#+_=j-I@BB zqn_=VpasvpkZ%E=GQkO*9&qksS`XyA4L8P2^geTKH{dn|Pj*dUYf(VjLW1iVz*R0> ze6Bj`=Xa+bQPMuH(naLKu{J_dwMRP*ino|u6eO>|Yrz3%LP+Ipe^gL#|9%n4bDpM` z_SM*ioyV>f-)Vx%v+co!d$kMd2ry{Fm7T8)35meAwn2zxN+{@*D>1Q)-0mFo15Vvo z@k0#4Il@C<5RkmFvPwN7-LV)pM$k99EvhvIF<+yu{r!aSlWhP(@1Y13hEDXl z6jQ1Z_8+R0%To)V zA_Ab?vn$BX&TfHd*uVM3E&f3{y{OB{(zJ_!XVO@55@uKo%=Q6_EhOr&JsM(_jUsbR z6P2f?g<+Fj2lf%8gK+b4&Z9Xhl525|DEk7qPxjp25baE;?&+a~2|%=ftz2=txm#j9 zN4G+w=e-5*cSfO8?ni%Esry&oS&KAs=K-_WS0W67wRGC?tTCX;FlsM$WfzJq*w;A_UlM1;3K z$@yFRxxgFop>#j7@$(mbUg&WF+uIclCZMqTvM3@A^lD{gvy=9-0UiDbtIxvmQ(!)u zI`;V!pBL<6!5R0n;AJxswgk#jgzAuDIeQ{}#s*Xo$#VtGqY1HCdB(-ZK7R7#N6){i zUtXNBfV6@J%Sgd^x}`EaLOo)9_QdMXtN6TN{NlHezkV8i{apF~Hr2p8Uv5>;2E_mQ zM>50b^{kru{i@?1@BXw@44G9v|G0GN62v3dUG{u_#Eje05%pJ>%BodG;9I-22eGxP zKGerNZolT5I+UCz_|p@Lq{J+PfB5hD=cD~Ac|Uo5(dqln_r=?{=a}1$Y`OPf+u1(6yh;6H81K-#MP zdhah678FDfd@gOf8T}o#yvvY|ANbRzeBQ%C#E zm?xk7{C9sWeAxWW&q3NE3Avy^GtG>);Ct6nmyU7NOhftqhcmcpfCyXDdAX3o;S>~{ zP}~?|s0toZr0w_Tn{aL&a#uAg_-@S88reSY&Z*KF1OClQ1~ffHk@ zGLl<)D9-B3(0a$po_}q~G4nH@uhsCwU;h62gR59@Mn1oLA;0TSVODckKl9JO`tySR zpTFRbUwo_jrw{+}<5egB`{(~XGXK2@{(F1;cO+Q#-;3b?%Zp%f1g~5=<$dH&v)<>$ z1V}1P4IvGc-1$5|IhIfyZ&GL^WTZE d#WLCIRqeFo=qG1?EkSkwecIw5C8w_Z@;~a=_MZR% literal 0 HcmV?d00001 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/schematicsGuide.png b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/schematicsGuide.png new file mode 100644 index 0000000000000000000000000000000000000000..6933489b9edb613b2bd450717849eefcf7dcfc49 GIT binary patch literal 52343 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 literal 0 HcmV?d00001 diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/thumb.png b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..806960498486782b91c90ee37aa12b1651d8c9ee GIT binary patch literal 31021 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 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 () { + hideAgentDownloadPopup(); + }); + + }); +} + +function downloadAgent() { + var deviceName; + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + var deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/; + if (deviceName && deviceNameFormat.test(deviceName)) { + $('#downloadForm').submit(); + hideAgentDownloadPopup(); + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + showAgentDownloadPopup(); + setTimeout(function () { + hideAgentDownloadPopup(); + }, 1000); + } 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 == "200") { + $(modalPopupContent).html($('#download-device-modal-content-links').html()); + $("input#download-device-url").val(data.responseText); + $("input#download-device-url").focus(function () { + $(this).select(); + }); + showAgentDownloadPopup(); + } else if (data.status == "401") { + $(modalPopupContent).html($('#device-401-content').html()); + $("#device-401-link").click(function () { + window.location = "/devicemgt/login"; + }); + showAgentDownloadPopup(); + } else if (data == "403") { + $(modalPopupContent).html($('#device-403-content').html()); + $("#device-403-link").click(function () { + window.location = "/devicemgt/login"; + }); + showAgentDownloadPopup(); + } else { + $(modalPopupContent).html($('#device-unexpected-error-content').html()); + $("a#device-unexpected-error-link").click(function () { + hideAgentDownloadPopup(); + }); + } +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/js/jquery.validate.js b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/js/jquery.validate.js new file mode 100644 index 000000000..fe7ecf07a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/public/js/jquery.validate.js @@ -0,0 +1,1227 @@ +/* + * 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/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.hbs b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.hbs new file mode 100644 index 000000000..a27f5547a --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.hbs @@ -0,0 +1,297 @@ +

      +
      + +
      +
      + +
      +
      +

      What it Does

      +
      +

      A Virtual Device that mimics the functionality of a real Firealarm. + Once run, the Virtual Firealarm will connect to WSO2 IoTServer and + push Temperature readings.

      +

      The device supports MQTT and XMPP Communications. It is configured to use MQTT by + default.

      +
      +

      What You Need

      +
      +
        +
      • + STEP 01 +    Go ahead and [Download] the Device. +
      • +
      • + STEP 02 +    Proceed to [Prepare] section. +
      • +
      • + STEP 03 +    Read [Try Out] section to further experiment with the device. +
      • +
      +
      + View API
        + + + Download Agent +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +

      +
      +
      +

      Prepare

      +
      +
        +
      • + 01 +    Download your VirtualFireAlarm using [Download Agent] button above. +
      • +
      • + 02 +    Unzip the downloaded Agent. +
      • +
      • + 03 +    Move into the unzipped Agent folder in the terminal. +
      • +
      • + 04 +    Unzip the downloaded Agent and start terminal to run this command: [sh + start-device.sh] +
      • +
      +
      +
      +
      +

      The Virtual-Fire-Alarm Device

      +
      +

      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 and monitor Real-Time data. +
      • +
      • + 03 +    You can also view analytics of the data published to IoT-Server by + navigating to Device Analytics page. +
      • +
      +
      +

      Click on the image to zoom

      +
      + + + +
      +
      + +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + {{js "/js/jquery.validate.js"}} +{{/zone}} diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.json b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.virtual_firealarm.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/iot-plugins/virtual-fire-alarm-plugin/pom.xml b/components/iot-plugins/virtual-fire-alarm-plugin/pom.xml new file mode 100644 index 000000000..7bac29dcd --- /dev/null +++ b/components/iot-plugins/virtual-fire-alarm-plugin/pom.xml @@ -0,0 +1,64 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + virtual-fire-alarm-plugin + pom + WSO2 Carbon - Arduino Plugin + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl + org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl + org.wso2.carbon.device.mgt.iot.virtualfirealarm.ui + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl + org.wso2.carbon.device.mgt.iot.virtualfirealarm.analytics + org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/pom.xml b/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/pom.xml deleted file mode 100644 index 2f548409a..000000000 --- a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - org.wso2.carbon.devicemgt-plugins - key-mgt - 1.9.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.key.mgt.handler.valve - 1.9.0-SNAPSHOT - bundle - WSO2 Carbon - Key Management Handler Valve - WSO2 Carbon - Key Management Handler Valve - http://wso2.org - - - - - org.apache.felix - maven-bundle-plugin - true - - - ${project.artifactId} - ${project.artifactId} - org.wso2.carbon.tomcat.patch - - org.wso2.carbon.key.mgt.handler.valve.* - - tomcat - - - - - - - - - org.apache.tomcat.wso2 - tomcat - - - org.wso2.carbon - org.wso2.carbon.apimgt.core - - - org.wso2.carbon - org.wso2.carbon.apimgt.impl - - - org.wso2.carbon - org.wso2.carbon.logging - - - org.wso2.carbon - org.wso2.carbon.tomcat.ext - - - - - diff --git a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerUtil.java b/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerUtil.java deleted file mode 100644 index 69a430380..000000000 --- a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerUtil.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.key.mgt.handler.valve; - -import org.apache.axiom.om.OMAbstractFactory; -import org.apache.axiom.om.OMElement; -import org.apache.axiom.om.OMFactory; -import org.apache.axiom.om.OMNamespace; -import org.apache.catalina.connector.Response; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.apimgt.api.APIManagementException; -import org.wso2.carbon.apimgt.core.APIManagerErrorConstants; -import org.wso2.carbon.apimgt.core.authenticate.APITokenValidator; -import org.wso2.carbon.apimgt.impl.APIConstants; -import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.identity.base.IdentityException; -import org.wso2.carbon.identity.core.util.IdentityUtil; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; - -public class HandlerUtil { - - private static APIKeyValidationInfoDTO apiKeyValidationDTO; - private static final Log log = LogFactory.getLog(HandlerUtil.class); - - /** - * Retrieve bearer token form the HTTP header - * @param bearerToken Bearer Token extracted out of the corresponding HTTP header - */ - public static String getAccessToken(String bearerToken) { - String accessToken = null; - String[] token = bearerToken.split(HandlerConstants.TOKEN_NAME_BEARER); - if (token.length > 1 && token[1] != null) { - accessToken = token[1].trim(); - } - return accessToken; - } - - public static String getAPIVersion(HttpServletRequest request) { - int contextStartsIndex = (request.getRequestURI()).indexOf(request.getContextPath()) + 1; - int length = request.getContextPath().length(); - String afterContext = (request.getRequestURI()).substring(contextStartsIndex + length); - int SlashIndex = afterContext.indexOf(("/")); - - if (SlashIndex != -1) { - return afterContext.substring(0, SlashIndex); - } else { - return afterContext; - } - } - - public static void handleNoMatchAuthSchemeCallForRestService(Response response,String httpVerb, String reqUri, - String version, String context ) { - String errMsg = "Resource is not matched for HTTP Verb " + httpVerb + ". API context " + context + - ",version " + version + ", request " + reqUri; - APIFaultException e = new APIFaultException( APIManagerErrorConstants.API_AUTH_INCORRECT_API_RESOURCE, errMsg); - String faultPayload = getFaultPayload(e, APIManagerErrorConstants.API_SECURITY_NS, - APIManagerErrorConstants.API_SECURITY_NS_PREFIX).toString(); - handleRestFailure(response, faultPayload); - } - - public static boolean doAuthenticate(String context, String version, String accessToken, - String requiredAuthenticationLevel, String clientDomain) - throws APIManagementException, - APIFaultException { - - if (APIConstants.AUTH_NO_AUTHENTICATION.equals(requiredAuthenticationLevel)) { - return true; - } - APITokenValidator tokenValidator = new APITokenValidator(); - apiKeyValidationDTO = tokenValidator.validateKey(context, version, accessToken, - requiredAuthenticationLevel, clientDomain); - if (apiKeyValidationDTO.isAuthorized()) { - String userName = apiKeyValidationDTO.getEndUserName(); - PrivilegedCarbonContext.getThreadLocalCarbonContext() - .setUsername(apiKeyValidationDTO.getEndUserName()); - try { - PrivilegedCarbonContext.getThreadLocalCarbonContext() - .setTenantId(IdentityUtil.getTenantIdOFUser(userName)); - } catch (IdentityException e) { - log.error("Error while retrieving Tenant Id", e); - return false; - } - return true; - } else { - throw new APIFaultException(apiKeyValidationDTO.getValidationStatus(), - "Access failure for API: " + context + ", version: " + - version + " with key: " + accessToken); - } - } - - public static void handleRestFailure(Response response, String payload) { - response.setStatus(403); - response.setContentType("application/xml"); - response.setCharacterEncoding("UTF-8"); - try { - response.getWriter().write(payload); - } catch (IOException e) { - log.error("Error in sending fault response", e); - } - } - - public static OMElement getFaultPayload(APIFaultException exception, String FaultNS, - String FaultNSPrefix) { - OMFactory fac = OMAbstractFactory.getOMFactory(); - OMNamespace ns = fac.createOMNamespace(FaultNS, FaultNSPrefix); - OMElement payload = fac.createOMElement("fault", ns); - - OMElement errorCode = fac.createOMElement("code", ns); - errorCode.setText(String.valueOf(exception.getErrorCode())); - OMElement errorMessage = fac.createOMElement("message", ns); - errorMessage.setText(APIManagerErrorConstants.getFailureMessage(exception.getErrorCode())); - OMElement errorDetail = fac.createOMElement("description", ns); - errorDetail.setText(exception.getMessage()); - - payload.addChild(errorCode); - payload.addChild(errorMessage); - payload.addChild(errorDetail); - return payload; - } - -} diff --git a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/OAuthTokenValidatorValve.java b/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/OAuthTokenValidatorValve.java deleted file mode 100644 index 23fd9a8f9..000000000 --- a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/OAuthTokenValidatorValve.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.key.mgt.handler.valve; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.valves.ValveBase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.apimgt.api.APIManagementException; -import org.wso2.carbon.apimgt.core.authenticate.APITokenValidator; -import org.wso2.carbon.apimgt.core.gateway.APITokenAuthenticator; -import org.wso2.carbon.apimgt.impl.APIConstants; -import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; -import org.wso2.carbon.apimgt.impl.utils.APIUtil; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.Enumeration; - -public class OAuthTokenValidatorValve extends ValveBase { - - private static final Log log = LogFactory.getLog(OAuthTokenValidatorValve.class); - - APITokenAuthenticator authenticator; - - public OAuthTokenValidatorValve() { - authenticator = new APITokenAuthenticator(); - } - - @Override - public void invoke(Request request, Response response) throws java.io.IOException, javax.servlet.ServletException { - String context = request.getContextPath(); - if (context == null || context.equals("")) { - //Invoke the next valve in handler chain. - getNext().invoke(request, response); - return; - } - - boolean contextExist; - Boolean contextValueInCache = null; - if (APIUtil.getAPIContextCache().get(context) != null) { - contextValueInCache = Boolean.parseBoolean(APIUtil.getAPIContextCache().get(context).toString()); - } - - if (contextValueInCache != null) { - contextExist = contextValueInCache; - } else { - contextExist = ApiMgtDAO.isContextExist(context); - APIUtil.getAPIContextCache().put(context, contextExist); - } - - if (!contextExist) { - getNext().invoke(request, response); - return; - } - - try { - handleWSDLGetRequest(request, response, context); - } catch (IOException e) { - e.printStackTrace(); - } catch (ServletException e) { - e.printStackTrace(); - } - - String authHeader = request.getHeader(APIConstants.OperationParameter.AUTH_PARAM_NAME); - String accessToken = null; - - /* Authenticate*/ - try { - if (authHeader != null) { - accessToken = HandlerUtil.getAccessToken(authHeader); - } else { - // There can be some API published with None Auth Type - /* - * throw new - * APIFaultException(APIConstants.KeyValidationStatus - * .API_AUTH_INVALID_CREDENTIALS, - * "Invalid format for Authorization header. Expected 'Bearer '" - * ); - */ - } - - String apiVersion = HandlerUtil.getAPIVersion(request); - String domain = request.getHeader(APITokenValidator.getAPIManagerClientDomainHeader()); - String authLevel = authenticator.getResourceAuthenticationScheme(context, - apiVersion, - request.getRequestURI(), - request.getMethod()); - if (HandlerConstants.NO_MATCHING_AUTH_SCHEME.equals(authLevel)) { - HandlerUtil.handleNoMatchAuthSchemeCallForRestService(response, - request.getMethod(), request.getRequestURI(), - apiVersion, context); - return; - } else { - HandlerUtil.doAuthenticate(context, apiVersion, accessToken, authLevel, domain); - } - } catch (APIManagementException e) { - //ignore - } catch (APIFaultException e) { - log.error("Error occurred while key validation", e); - return; - } - - getNext().invoke(request, response); - } - - private void handleWSDLGetRequest(Request request, Response response, - String context) throws IOException, ServletException { - if (request.getMethod().equals("GET")) { - // TODO:Need to get these paths from a config file. - if (request.getRequestURI().matches(context + "/[^/]*/services")) { - getNext().invoke(request, response); - return; - } - Enumeration params = request.getParameterNames(); - String paramName; - while (params.hasMoreElements()) { - paramName = params.nextElement(); - if (paramName.endsWith("wsdl") || paramName.endsWith("wadl")) { - getNext().invoke(request, response); - return; - } - } - } - } - -} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml new file mode 100644 index 000000000..0da2c6395 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml @@ -0,0 +1,180 @@ + + + + + + android-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.android.agent + WSO2 Carbon - Android JAX-RS API + Android JAX-RS API + war + + + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + maven-war-plugin + 2.2 + + WEB-INF/lib/*cxf*.jar + ${project.artifactId} + + + + + + + + deploy + + compile + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + compile + + run + + + + + + + + + + + + + + + + + + + client + + test + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + test + + java + + + + + + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-frontend-jaxrs + + + org.apache.cxf + cxf-rt-transports-http + + + javax.ws.rs + jsr311-api + provided + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + org.wso2.carbon + org.wso2.carbon.logging + provided + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + provided + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.android + provided + + + + commons-httpclient.wso2 + commons-httpclient + provided + + + + com.google.code.gson + gson + + + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/ConfigurationMgtService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/ConfigurationMgtService.java new file mode 100644 index 000000000..565393e49 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/ConfigurationMgtService.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.license.mgt.License; +import org.wso2.carbon.mdm.services.android.exception.AndroidAgentException; +import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils; +import org.wso2.carbon.mdm.services.android.util.AndroidConstants; +import org.wso2.carbon.mdm.services.android.util.Message; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; + +/** + * Android Platform Configuration REST-API implementation. + * All end points supports JSON, XMl with content negotiation. + */ +@WebService +@Produces({ "application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class ConfigurationMgtService { + + private static Log log = LogFactory.getLog(ConfigurationMgtService.class); + + @POST + public Message configureSettings(TenantConfiguration configuration) + throws AndroidAgentException { + + Message responseMsg = new Message(); + String msg; + ConfigurationEntry licenseEntry = null; + try { + configuration.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + List configs = configuration.getConfiguration(); + for(ConfigurationEntry entry : configs){ + if(AndroidConstants.TenantConfigProperties.LICENSE_KEY.equals(entry.getName())){ + License license = new License(); + license.setName(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + license.setLanguage(AndroidConstants.TenantConfigProperties.LANGUAGE_US); + license.setVersion("1.0.0"); + license.setText(entry.getValue().toString()); + AndroidAPIUtils.getDeviceManagementService().addLicense(DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, license); + licenseEntry = entry; + break; + } + } + + if(licenseEntry != null) { + configs.remove(licenseEntry); + } + configuration.setConfiguration(configs); + AndroidAPIUtils.getDeviceManagementService().saveConfiguration(configuration); + Response.status(Response.Status.CREATED); + responseMsg.setResponseMessage("Android platform configuration saved successfully."); + responseMsg.setResponseCode(Response.Status.CREATED.toString()); + } catch (DeviceManagementException e) { + msg = "Error occurred while configuring the android platform"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMsg; + } + + @GET + public TenantConfiguration getConfiguration() throws AndroidAgentException { + String msg; + TenantConfiguration tenantConfiguration; + List configs; + try { + tenantConfiguration = AndroidAPIUtils.getDeviceManagementService(). + getConfiguration(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + if(tenantConfiguration != null) { + configs = tenantConfiguration.getConfiguration(); + } else { + tenantConfiguration = new TenantConfiguration(); + configs = new ArrayList(); + } + + ConfigurationEntry entry = new ConfigurationEntry(); + License license = AndroidAPIUtils.getDeviceManagementService().getLicense( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, AndroidConstants. + TenantConfigProperties.LANGUAGE_US); + + if(license != null && configs != null) { + entry.setContentType(AndroidConstants.TenantConfigProperties.CONTENT_TYPE_TEXT); + entry.setName(AndroidConstants.TenantConfigProperties.LICENSE_KEY); + entry.setValue(license.getText()); + configs.add(entry); + tenantConfiguration.setConfiguration(configs); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while retrieving the Android tenant configuration"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return tenantConfiguration; + } + + @PUT + public Message updateConfiguration(TenantConfiguration configuration) throws AndroidAgentException { + String msg; + Message responseMsg = new Message(); + ConfigurationEntry licenseEntry = null; + try { + configuration.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + List configs = configuration.getConfiguration(); + for(ConfigurationEntry entry : configs){ + if(AndroidConstants.TenantConfigProperties.LICENSE_KEY.equals(entry.getName())){ + License license = new License(); + license.setName(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + license.setLanguage(AndroidConstants.TenantConfigProperties.LANGUAGE_US); + license.setVersion("1.0.0"); + license.setText(entry.getValue().toString()); + AndroidAPIUtils.getDeviceManagementService().addLicense(DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, license); + licenseEntry = entry; + } + } + + if(licenseEntry != null) { + configs.remove(licenseEntry); + } + configuration.setConfiguration(configs); + AndroidAPIUtils.getDeviceManagementService().saveConfiguration(configuration); + Response.status(Response.Status.ACCEPTED); + responseMsg.setResponseMessage("Android platform configuration has updated successfully."); + responseMsg.setResponseCode(Response.Status.ACCEPTED.toString()); + } catch (DeviceManagementException e) { + msg = "Error occurred while modifying configuration settings of Android platform"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMsg; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/DeviceManagementService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/DeviceManagementService.java new file mode 100644 index 000000000..a6be42cdc --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/DeviceManagementService.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.services.android; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +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.license.mgt.License; +import org.wso2.carbon.mdm.services.android.exception.AndroidAgentException; +import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils; +import org.wso2.carbon.mdm.services.android.util.Message; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Android Device Management REST-API implementation. + * All end points supports JSON, XMl with content negotiation. + */ +@WebService +@Produces({ "application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class DeviceManagementService { + + private static Log log = LogFactory.getLog(DeviceManagementService.class); + + /** + * Get all devices.Returns list of Android devices registered in MDM. + * + * @return Device List + * @throws org.wso2.carbon.mdm.services.android.exception.AndroidAgentException + */ + @GET + public List getAllDevices() + throws AndroidAgentException { + String msg; + List devices; + + try { + devices = AndroidAPIUtils.getDeviceManagementService(). + getAllDevices(DeviceManagementConstants.MobileDeviceTypes. + MOBILE_DEVICE_TYPE_ANDROID); + } catch (DeviceManagementException e) { + msg = "Error occurred while fetching the device list."; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return devices; + } + + /** + * Fetch Android device details of a given device Id. + * + * @param id Device Id + * @return Device + * @throws org.wso2.carbon.mdm.services.android.exception.AndroidAgentException + */ + @GET + @Path("{id}") + public org.wso2.carbon.device.mgt.common.Device getDevice(@PathParam("id") String id) + throws AndroidAgentException { + + String msg; + org.wso2.carbon.device.mgt.common.Device device; + + try { + DeviceIdentifier deviceIdentifier = AndroidAPIUtils.convertToDeviceIdentifierObject(id); + device = AndroidAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier); + if (device == null) { + Response.status(Response.Status.NOT_FOUND); + } + } catch (DeviceManagementException deviceMgtEx) { + msg = "Error occurred while fetching the device information."; + log.error(msg, deviceMgtEx); + throw new AndroidAgentException(msg, deviceMgtEx); + } + return device; + } + + /** + * Update Android device details of given device id. + * + * @param id Device Id + * @param device Device Details + * @return Message + * @throws AndroidAgentException + */ + @PUT + @Path("{id}") + public Message updateDevice(@PathParam("id") String id, Device device) + throws AndroidAgentException { + String msg; + Message responseMessage = new Message(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(id); + deviceIdentifier + .setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + boolean result; + try { + device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + result = AndroidAPIUtils.getDeviceManagementService() + .updateDeviceInfo(deviceIdentifier, device); + if (result) { + Response.status(Response.Status.ACCEPTED); + responseMessage.setResponseMessage("Device information has modified successfully."); + } else { + Response.status(Response.Status.NOT_MODIFIED); + responseMessage.setResponseMessage("Device not found for the update."); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while modifying the device information."; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMessage; + } + + @POST + @Path("appList/{id}") + public Message updateApplicationList(@PathParam("id") String id, List applications) + throws + AndroidAgentException { + + Message responseMessage = new Message(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(id); + deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + try { + AndroidAPIUtils.getApplicationManagerService(). + updateApplicationListInstalledInDevice(deviceIdentifier, applications); + Response.status(Response.Status.ACCEPTED); + responseMessage.setResponseMessage("Device information has modified successfully."); + + } catch (ApplicationManagementException e) { + String msg = "Error occurred while modifying the application list."; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMessage; + } + + @GET + @Path("license") + @Produces("text/html") + public String getLicense() throws AndroidAgentException { + License license; + + try { + license = + AndroidAPIUtils.getDeviceManagementService().getLicense( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, + DeviceManagementConstants.LanguageCodes.LANGUAGE_CODE_ENGLISH_US); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the license configured for Android device enrolment"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return (license == null) ? null : license.getText(); + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/EnrollmentService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/EnrollmentService.java new file mode 100644 index 000000000..5ecf373e7 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/EnrollmentService.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.services.android; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.mdm.services.android.exception.AndroidAgentException; +import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils; +import org.wso2.carbon.mdm.services.android.util.Message; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + +/** + * Android Device Enrollment REST-API implementation. + * All end points supports JSON, XMl with content negotiation. + */ +@WebService +@Produces({ "application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class EnrollmentService { + + private static Log log = LogFactory.getLog(EnrollmentService.class); + + @POST + public Message enrollDevice(org.wso2.carbon.device.mgt.common.Device device) + throws AndroidAgentException { + + Message responseMsg = new Message(); + String msg; + try { + device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + device.getEnrolmentInfo().setOwner(AndroidAPIUtils.getAuthenticatedUser()); + boolean status = AndroidAPIUtils.getDeviceManagementService().enrollDevice(device); + if (status) { + Response.status(Response.Status.CREATED); + responseMsg.setResponseMessage("Device enrollment succeeded."); + responseMsg.setResponseCode(Response.Status.CREATED.toString()); + } else { + Response.status(Response.Status.INTERNAL_SERVER_ERROR); + responseMsg.setResponseMessage("Device enrollment failed."); + responseMsg.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while enrolling the device"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMsg; + } + + @GET + @Path("{deviceId}") + public Message isEnrolled(@PathParam("deviceId") String id) throws AndroidAgentException { + String msg; + boolean result; + Message responseMsg = new Message(); + DeviceIdentifier deviceIdentifier = AndroidAPIUtils.convertToDeviceIdentifierObject(id); + + try { + result = AndroidAPIUtils.getDeviceManagementService().isEnrolled(deviceIdentifier); + if (result) { + responseMsg.setResponseMessage("Device has already enrolled"); + responseMsg.setResponseCode(Response.Status.ACCEPTED.toString()); + Response.status(Response.Status.ACCEPTED); + } else { + responseMsg.setResponseMessage("Device not found"); + responseMsg.setResponseCode(Response.Status.NOT_FOUND.toString()); + Response.status(Response.Status.NOT_FOUND); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while enrollment of the device."; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMsg; + } + + @PUT + @Path("{deviceId}") + public Message modifyEnrollment(@PathParam("deviceId") String id, + org.wso2.carbon.device.mgt.common.Device device) + throws AndroidAgentException { + String msg; + boolean result; + Message responseMsg = new Message(); + try { + device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + result = AndroidAPIUtils.getDeviceManagementService().modifyEnrollment(device); + if (result) { + responseMsg.setResponseMessage("Device enrollment has updated successfully"); + responseMsg.setResponseCode(Response.Status.ACCEPTED.toString()); + Response.status(Response.Status.ACCEPTED); + } else { + responseMsg.setResponseMessage("Device not found for enrollment"); + responseMsg.setResponseCode(Response.Status.NOT_MODIFIED.toString()); + Response.status(Response.Status.NOT_MODIFIED); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while modifying enrollment of the device"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMsg; + } + + @DELETE + @Path("{deviceId}") + public Message disEnrollDevice(@PathParam("deviceId") String id) throws AndroidAgentException { + Message responseMsg = new Message(); + boolean result; + String msg; + DeviceIdentifier deviceIdentifier = AndroidAPIUtils.convertToDeviceIdentifierObject(id); + + try { + result = AndroidAPIUtils.getDeviceManagementService().disenrollDevice(deviceIdentifier); + if (result) { + responseMsg.setResponseMessage("Device has removed successfully"); + responseMsg.setResponseCode(Response.Status.ACCEPTED.toString()); + Response.status(Response.Status.ACCEPTED); + } else { + responseMsg.setResponseMessage("Device not found"); + responseMsg.setResponseCode(Response.Status.NOT_FOUND.toString()); + Response.status(Response.Status.NOT_FOUND); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while dis enrolling the device"; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMsg; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/OperationMgtService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/OperationMgtService.java new file mode 100644 index 000000000..91329cc94 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/OperationMgtService.java @@ -0,0 +1,931 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException; +import org.wso2.carbon.device.mgt.common.notification.mgt.*; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation; +import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; +import org.wso2.carbon.mdm.services.android.bean.*; +import org.wso2.carbon.mdm.services.android.bean.Notification; +import org.wso2.carbon.mdm.services.android.bean.wrapper.*; +import org.wso2.carbon.mdm.services.android.exception.AndroidOperationException; +import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils; +import org.wso2.carbon.mdm.services.android.util.AndroidConstants; +import org.wso2.carbon.mdm.services.android.util.AndroidDeviceUtils; +import org.wso2.carbon.mdm.services.android.util.Message; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Android Device Operation REST-API implementation. + */ +public class OperationMgtService { + + private static Log log = LogFactory.getLog(OperationMgtService.class); + private static final String ACCEPT = "Accept"; + private static final String OPERATION_ERROR_STATUS = "ERROR"; + private static final String DEVICE_TYPE_ANDROID = "android"; + + @PUT + @Path("{id}") + public List getPendingOperations + (@HeaderParam(ACCEPT) String acceptHeader, @PathParam("id") String id, + List resultOperations) { + Message message; + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + + if (id == null || id.isEmpty()) { + String errorMessage = "Device identifier is null or empty, hence returning device not found"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.BAD_REQUEST.toString()).build(); + log.error(errorMessage); + throw new AndroidOperationException(message, responseMediaType); + } + + DeviceIdentifier deviceIdentifier = AndroidAPIUtils.convertToDeviceIdentifierObject(id); + try { + if (!AndroidDeviceUtils.isValidDeviceIdentifier(deviceIdentifier)) { + String errorMessage = "Device not found for identifier '" + id + "'"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.BAD_REQUEST.toString()).build(); + log.error(errorMessage); + throw new AndroidOperationException(message, responseMediaType); + } + if (log.isDebugEnabled()) { + log.debug("Invoking Android pending operations:" + id); + } + if (resultOperations != null && !resultOperations.isEmpty()) { + updateOperations(id, resultOperations); + } + } catch (OperationManagementException e) { + log.error("Issue in retrieving operation management service instance", e); + } catch (PolicyComplianceException e) { + log.error("Issue in updating Monitoring operation"); + } catch (DeviceManagementException e) { + log.error("Issue in retrieving device management service instance", e); + } catch (ApplicationManagementException e) { + log.error("Issue in retrieving application management service instance", e); + } catch (NotificationManagementException e) { + log.error("Issue in retrieving Notification management service instance", e); + } + + List pendingOperations; + try { + pendingOperations = AndroidAPIUtils.getPendingOperations(deviceIdentifier); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + return pendingOperations; + } + + @POST + @Path("lock") + public Response configureDeviceLock(@HeaderParam(ACCEPT) String acceptHeader, List deviceIDs) { + + if (log.isDebugEnabled()) { + log.debug("Invoking Android device lock operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + Response response; + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.DEVICE_LOCK); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(true); + response = AndroidAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + return response; + } + + @POST + @Path("location") + public Response getDeviceLocation(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + if (log.isDebugEnabled()) { + log.debug("Invoking Android device location operation"); + } + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.DEVICE_LOCATION); + operation.setType(Operation.Type.COMMAND); + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, + message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("clear-password") + public Response removePassword(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + if (log.isDebugEnabled()) { + log.debug("Invoking Android clear password operation"); + } + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.CLEAR_PASSWORD); + operation.setType(Operation.Type.COMMAND); + + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, + message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("camera") + public Response configureCamera(@HeaderParam(ACCEPT) String acceptHeader, + CameraBeanWrapper cameraBeanWrapper) { + + if (log.isDebugEnabled()) { + log.debug("Invoking Android Camera operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + Camera camera = cameraBeanWrapper.getOperation(); + + if (camera == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the configure camera operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new camera instance"); + } + + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.CAMERA); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(camera.isEnabled()); + + return AndroidAPIUtils.getOperationResponse(cameraBeanWrapper.getDeviceIDs(), operation, message, + responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("device-info") + public Response getDeviceInformation(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + + if (log.isDebugEnabled()) { + log.debug("Invoking get Android device information operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.DEVICE_INFO); + operation.setType(Operation.Type.COMMAND); + getApplications(acceptHeader, deviceIDs); + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, message, + responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("enterprise-wipe") + public Response wipeDevice(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + + if (log.isDebugEnabled()) { + log.debug("Invoking enterprise-wipe device operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.ENTERPRISE_WIPE); + operation.setType(Operation.Type.COMMAND); + + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, message, + responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("wipe-data") + public Response wipeData(@HeaderParam(ACCEPT) String acceptHeader, + WipeDataBeanWrapper wipeDataBeanWrapper) { + + if (log.isDebugEnabled()) { + log.debug("Invoking Android wipe-data device operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + WipeData wipeData = wipeDataBeanWrapper.getOperation(); + + if (wipeData == null) { + throw new OperationManagementException("WipeData bean is empty"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.WIPE_DATA); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(wipeData.toJSON()); + + return AndroidAPIUtils.getOperationResponse(wipeDataBeanWrapper.getDeviceIDs(), operation, message, + responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("application-list") + public Response getApplications(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + + if (log.isDebugEnabled()) { + log.debug("Invoking Android getApplicationList device operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.APPLICATION_LIST); + operation.setType(Operation.Type.COMMAND); + + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, message, + responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("ring-device") + public Response ringDevice(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + + if (log.isDebugEnabled()) { + log.debug("Invoking Android ring-device device operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.DEVICE_RING); + operation.setType(Operation.Type.COMMAND); + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, message, + responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("mute") + public Response muteDevice(@HeaderParam(ACCEPT) String acceptHeader, + List deviceIDs) { + + if (log.isDebugEnabled()) { + log.debug("Invoking mute device operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.DEVICE_MUTE); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(true); + return AndroidAPIUtils.getOperationResponse(deviceIDs, operation, message, + responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("install-application") + public Response installApplication(@HeaderParam(ACCEPT) String acceptHeader, + ApplicationInstallationBeanWrapper applicationInstallationBeanWrapper) { + + if (log.isDebugEnabled()) { + log.debug("Invoking 'InstallApplication' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + ApplicationInstallation applicationInstallation = applicationInstallationBeanWrapper.getOperation(); + + if (applicationInstallation == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the application installing operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new application installation instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.INSTALL_APPLICATION); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(applicationInstallation.toJSON()); + + return AndroidAPIUtils.getOperationResponse(applicationInstallationBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("uninstall-application") + public Response uninstallApplication(@HeaderParam(ACCEPT) String acceptHeader, + ApplicationUninstallationBeanWrapper applicationUninstallationBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'UninstallApplication' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + ApplicationUninstallation applicationUninstallation = applicationUninstallationBeanWrapper.getOperation(); + + if (applicationUninstallation == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the application uninstalling operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new application uninstallation instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.UNINSTALL_APPLICATION); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(applicationUninstallation.toJSON()); + + return AndroidAPIUtils.getOperationResponse(applicationUninstallationBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("blacklist-applications") + public Response blacklistApplications(@HeaderParam(ACCEPT) String acceptHeader, + BlacklistApplicationsBeanWrapper blacklistApplicationsBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'Blacklist-Applications' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + BlacklistApplications blacklistApplications = blacklistApplicationsBeanWrapper.getOperation(); + + if (blacklistApplications == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the blacklisting apps operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new blacklist applications instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.BLACKLIST_APPLICATIONS); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(blacklistApplications.toJSON()); + + return AndroidAPIUtils.getOperationResponse(blacklistApplicationsBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("notification") + public Response sendNotification(@HeaderParam(ACCEPT) String acceptHeader, + NotificationBeanWrapper notificationBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'notification' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + Notification notification = notificationBeanWrapper.getOperation(); + + if (notification == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the notification operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new notification instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.NOTIFICATION); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(notification.toJSON()); + + return AndroidAPIUtils.getOperationResponse(notificationBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("wifi") + public Response configureWifi(@HeaderParam(ACCEPT) String acceptHeader, + WifiBeanWrapper wifiBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'configure wifi' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + Wifi wifi = wifiBeanWrapper.getOperation(); + + if (wifi == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the wifi operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new Wifi instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.WIFI); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(wifi.toJSON()); + + return AndroidAPIUtils.getOperationResponse(wifiBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("encrypt") + public Response encryptStorage(@HeaderParam(ACCEPT) String acceptHeader, + EncryptionBeanWrapper encryptionBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'encrypt' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + DeviceEncryption deviceEncryption = encryptionBeanWrapper.getOperation(); + + if (deviceEncryption == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the device encryption operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new encryption instance"); + } + + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.ENCRYPT_STORAGE); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(deviceEncryption.isEncrypted()); + + return AndroidAPIUtils.getOperationResponse(encryptionBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("change-lock-code") + public Response changeLockCode(@HeaderParam(ACCEPT) String acceptHeader, + LockCodeBeanWrapper lockCodeBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'change lock code' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + LockCode lockCode = lockCodeBeanWrapper.getOperation(); + + if (lockCode == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the change lock code operation is incorrect"); + } + throw new OperationManagementException("Issue in retrieving a new lock-code instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.CHANGE_LOCK_CODE); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(lockCode.toJSON()); + + return AndroidAPIUtils.getOperationResponse(lockCodeBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("password-policy") + public Response setPasswordPolicy(@HeaderParam(ACCEPT) String acceptHeader, + PasswordPolicyBeanWrapper passwordPolicyBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'password policy' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + PasscodePolicy passcodePolicy = passwordPolicyBeanWrapper.getOperation(); + + if (passcodePolicy == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the change password policy operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new Password policy instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.PASSCODE_POLICY); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(passcodePolicy.toJSON()); + + return AndroidAPIUtils.getOperationResponse(passwordPolicyBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("webclip") + public Response setWebClip(@HeaderParam(ACCEPT) String acceptHeader, + WebClipBeanWrapper webClipBeanWrapper) { + if (log.isDebugEnabled()) { + log.debug("Invoking 'webclip' operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + WebClip webClip = webClipBeanWrapper.getOperation(); + + if (webClip == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the add webclip operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new web clip instance"); + } + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(AndroidConstants.OperationCodes.WEBCLIP); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(webClip.toJSON()); + + return AndroidAPIUtils.getOperationResponse(webClipBeanWrapper.getDeviceIDs(), + operation, message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + @POST + @Path("disenroll") + public Response setDisenrollment(@HeaderParam(ACCEPT) String acceptHeader, + DisenrollmentBeanWrapper disenrollmentBeanWrapper) { + + if (log.isDebugEnabled()) { + log.debug("Invoking Android device disenrollment operation"); + } + + MediaType responseMediaType = AndroidAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + try { + Disenrollment disenrollment = disenrollmentBeanWrapper.getOperation(); + + if (disenrollment == null) { + if (log.isDebugEnabled()) { + log.debug("The payload of the device disenrollment operation is incorrect"); + } + throw new OperationManagementException("Issue in creating a new disenrollment instance"); + } + + CommandOperation operation = new CommandOperation(); + operation.setCode(AndroidConstants.OperationCodes.DISENROLL); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(disenrollment.isEnabled()); + + return AndroidAPIUtils.getOperationResponse(disenrollmentBeanWrapper.getDeviceIDs(), operation, + message, responseMediaType); + + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message = Message.responseMessage(errorMessage). + responseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()).build(); + log.error(errorMessage, e); + throw new AndroidOperationException(message, responseMediaType); + } + } + + private void updateOperations(String deviceId, List operations) + throws OperationManagementException, PolicyComplianceException, + ApplicationManagementException, NotificationManagementException, DeviceManagementException { + for (org.wso2.carbon.device.mgt.common.operation.mgt.Operation operation : operations) { + AndroidAPIUtils.updateOperation(deviceId, operation); + if(operation.getStatus().equals(OPERATION_ERROR_STATUS)){ + org.wso2.carbon.device.mgt.common.notification.mgt.Notification notification = new + org.wso2.carbon.device.mgt.common.notification.mgt.Notification(); + DeviceIdentifier id = new DeviceIdentifier(); + id.setId(deviceId); + id.setType(DEVICE_TYPE_ANDROID); + String deviceName = AndroidAPIUtils.getDeviceManagementService().getDevice(id).getName(); + notification.setOperationId(operation.getId()); + notification.setStatus(org.wso2.carbon.device.mgt.common.notification.mgt.Notification. + Status.NEW.toString()); + notification.setDeviceIdentifier(id); + notification.setDescription("Operation " + operation.getCode() + " failed to execute on device "+ + deviceName+". Device ID : " + deviceId); + AndroidAPIUtils.getNotificationManagementService().addNotification(notification); + } + if (log.isDebugEnabled()) { + log.debug("Updating operation '" + operation.toString() + "'"); + } + } + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/PolicyMgtService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/PolicyMgtService.java new file mode 100644 index 000000000..e2e9d2cb8 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/PolicyMgtService.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.mdm.services.android.exception.AndroidAgentException; +import org.wso2.carbon.mdm.services.android.util.AndroidAPIUtils; +import org.wso2.carbon.mdm.services.android.util.Message; +import org.wso2.carbon.policy.mgt.common.FeatureManagementException; +import org.wso2.carbon.policy.mgt.common.Policy; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.common.ProfileFeature; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + +@WebService +@Produces({"application/json", "application/xml"}) +@Consumes({"application/json", "application/xml"}) +public class PolicyMgtService { + + private static Log log = LogFactory.getLog(PolicyMgtService.class); + + @GET + @Path("{deviceId}") + public Message getEffectivePolicy(@HeaderParam("Accept") String acceptHeader, + @PathParam("deviceId") String id) throws AndroidAgentException { + + DeviceIdentifier deviceIdentifier = AndroidAPIUtils.convertToDeviceIdentifierObject(id); + Message responseMessage = new Message(); + Policy policy; + try { + PolicyManagerService policyManagerService = AndroidAPIUtils.getPolicyManagerService(); + policy = policyManagerService.getEffectivePolicy(deviceIdentifier); + if (policy == null) { + responseMessage = Message.responseMessage("No effective policy found"). + responseCode(Response.Status.NO_CONTENT.toString()).build(); + } else { + responseMessage = Message.responseMessage("Effective policy added to operation"). + responseCode(Response.Status.OK.toString()).build(); + } + } catch (PolicyManagementException e) { + String msg = "Error occurred while getting the policy."; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return responseMessage; + } + + @GET + @Path("/features/{deviceId}") + public List getEffectiveFeatures(@HeaderParam("Accept") String acceptHeader, + @PathParam("deviceId") String id) throws AndroidAgentException { + List profileFeatures; + DeviceIdentifier deviceIdentifier = AndroidAPIUtils.convertToDeviceIdentifierObject(id); + try { + PolicyManagerService policyManagerService = AndroidAPIUtils.getPolicyManagerService(); + profileFeatures = policyManagerService.getEffectiveFeatures(deviceIdentifier); + if (profileFeatures == null) { + Response.status(Response.Status.NOT_FOUND); + } + } catch (FeatureManagementException e) { + String msg = "Error occurred while getting the features."; + log.error(msg, e); + throw new AndroidAgentException(msg, e); + } + return profileFeatures; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/AndroidOperation.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/AndroidOperation.java new file mode 100644 index 000000000..297a5df75 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/AndroidOperation.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import com.google.gson.Gson; +/* +* This abstract class is used for extending generic functions with regard to operation. +*/ +public abstract class AndroidOperation { + + /* + * This method is used to convert operation object to a json format. + * + * @return json formatted String. + */ + public String toJSON() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationInstallation.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationInstallation.java new file mode 100644 index 000000000..e545c5bab --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationInstallation.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of install application operation. + */ +public class ApplicationInstallation extends AndroidOperation implements Serializable { + + private String appIdentifier; + private String type; + private String url; + + public String getAppIdentifier() { + return appIdentifier; + } + + public void setAppIdentifier(String appIdentifier) { + this.appIdentifier = appIdentifier; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationUninstallation.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationUninstallation.java new file mode 100644 index 000000000..5e0b2909f --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationUninstallation.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of uninstall application operation. + */ +public class ApplicationUninstallation extends AndroidOperation implements Serializable { + + private String appIdentifier; + private String type; + private String url; + private String name; + + public String getAppIdentifier() { + return appIdentifier; + } + + public void setAppIdentifier(String appIdentifier) { + this.appIdentifier = appIdentifier; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/BlacklistApplications.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/BlacklistApplications.java new file mode 100644 index 000000000..159ddfec9 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/BlacklistApplications.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; +import java.util.List; + +/** + * This class represents the blacklist applications information. + */ +public class BlacklistApplications extends AndroidOperation implements Serializable { + + private List appIdentifiers; + + public List getAppIdentifier() { + return appIdentifiers; + } + + public void setAppIdentifier(List appIdentifiers) { + this.appIdentifiers = appIdentifiers; + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Camera.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Camera.java new file mode 100644 index 000000000..2b392a19c --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Camera.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of camera operation. + */ +public class Camera extends AndroidOperation implements Serializable { + + private boolean enabled; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/DeviceEncryption.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/DeviceEncryption.java new file mode 100644 index 000000000..de81c94a5 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/DeviceEncryption.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of encrypt operation. + */ +public class DeviceEncryption extends AndroidOperation implements Serializable { + + private boolean encrypted; + + public boolean isEncrypted() { + return encrypted; + } + + public void setEncrypted(boolean encrypted) { + this.encrypted = encrypted; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Disenrollment.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Disenrollment.java new file mode 100644 index 000000000..8a1c2f8ac --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Disenrollment.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import java.io.Serializable; + +public class Disenrollment extends AndroidOperation implements Serializable { + + private boolean enabled; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/LockCode.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/LockCode.java new file mode 100644 index 000000000..a68ec2253 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/LockCode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of changing lock code operation. + */ +public class LockCode extends AndroidOperation implements Serializable { + + private String lockCode; + + public String getLockCode() { + return lockCode; + } + + public void setLockCode(String lockCode) { + this.lockCode = lockCode; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Notification.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Notification.java new file mode 100644 index 000000000..95e6b56f1 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Notification.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of sending notification operation. + */ +public class Notification extends AndroidOperation implements Serializable { + + private String message; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/PasscodePolicy.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/PasscodePolicy.java new file mode 100644 index 000000000..5142f9e63 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/PasscodePolicy.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of setting up password policy. + */ +public class PasscodePolicy extends AndroidOperation implements Serializable { + + private int maxFailedAttempts; + private int minLength; + private int pinHistory; + private int minComplexChars; + private int maxPINAgeInDays; + private boolean requireAlphanumeric; + private boolean allowSimple; + + public int getMaxFailedAttempts() { + return maxFailedAttempts; + } + + public void setMaxFailedAttempts(int maxFailedAttempts) { + this.maxFailedAttempts = maxFailedAttempts; + } + + public int getMinLength() { + return minLength; + } + + public void setMinLength(int minLength) { + this.minLength = minLength; + } + + public int getPinHistory() { + return pinHistory; + } + + public void setPinHistory(int pinHistory) { + this.pinHistory = pinHistory; + } + + public int getMinComplexChars() { + return minComplexChars; + } + + public void setMinComplexChars(int minComplexChars) { + this.minComplexChars = minComplexChars; + } + + public int getMaxPINAgeInDays() { + return maxPINAgeInDays; + } + + public void setMaxPINAgeInDays(int maxPINAgeInDays) { + this.maxPINAgeInDays = maxPINAgeInDays; + } + + public boolean isRequireAlphanumeric() { + return requireAlphanumeric; + } + + public void setRequireAlphanumeric(boolean requireAlphanumeric) { + this.requireAlphanumeric = requireAlphanumeric; + } + + public boolean isAllowSimple() { + return allowSimple; + } + + public void setAllowSimple(boolean allowSimple) { + this.allowSimple = allowSimple; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WebClip.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WebClip.java new file mode 100644 index 000000000..77fa8e18d --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WebClip.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of setting up webclip. + */ +public class WebClip extends AndroidOperation implements Serializable { + + private String identity; + private String title; + private String type; + + public String getIdentity() { + return identity; + } + + public void setIdentity(String identity) { + this.identity = identity; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Wifi.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Wifi.java new file mode 100644 index 000000000..97cee8634 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/Wifi.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of configuring wifi operation. + */ +public class Wifi extends AndroidOperation implements Serializable { + + private String ssid; + private String password; + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WipeData.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WipeData.java new file mode 100644 index 000000000..e3ba747cd --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/WipeData.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean; + +import java.io.Serializable; + +/** + * This class represents the information of wipedata operation. + */ +public class WipeData extends AndroidOperation implements Serializable { + + private String pin; + + public String getPin() { + return pin; + } + + public void setPin(String pin) { + this.pin = pin; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationInstallationBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationInstallationBeanWrapper.java new file mode 100644 index 000000000..ae809b8ee --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationInstallationBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.ApplicationInstallation; + +import java.util.List; + +/** + * This class is used to wrap the InstallApplication bean with devices. + */ +public class ApplicationInstallationBeanWrapper { + + private List deviceIDs; + private ApplicationInstallation operation; + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } + + public ApplicationInstallation getOperation() { + return operation; + } + + public void setOperation(ApplicationInstallation operation) { + this.operation = operation; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationUninstallationBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationUninstallationBeanWrapper.java new file mode 100644 index 000000000..ef34d97dc --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationUninstallationBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.ApplicationUninstallation; + +import java.util.List; + +/** + * This class is used to wrap the UninstallApplication bean with devices. + */ +public class ApplicationUninstallationBeanWrapper { + + private List deviceIDs; + private ApplicationUninstallation operation; + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } + + public ApplicationUninstallation getOperation() { + return operation; + } + + public void setOperation(ApplicationUninstallation operation) { + this.operation = operation; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/BlacklistApplicationsBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/BlacklistApplicationsBeanWrapper.java new file mode 100644 index 000000000..f74b0e863 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/BlacklistApplicationsBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.BlacklistApplications; + +import java.util.List; + +/** + * This class is used to wrap the BlacklistApplications bean with devices. + */ +public class BlacklistApplicationsBeanWrapper { + + private BlacklistApplications operation; + private List deviceIDs; + + public BlacklistApplications getOperation() { + return operation; + } + + public void setOperation(BlacklistApplications operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/CameraBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/CameraBeanWrapper.java new file mode 100644 index 000000000..4bbde3ac4 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/CameraBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.Camera; + +import java.util.List; + +/** + * This class is used to wrap the Camera bean with devices. + */ +public class CameraBeanWrapper { + + private Camera operation; + private List deviceIDs; + + public Camera getOperation() { + return operation; + } + + public void setOperation(Camera operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/DisenrollmentBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/DisenrollmentBeanWrapper.java new file mode 100644 index 000000000..c4d22061e --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/DisenrollmentBeanWrapper.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.Disenrollment; + +import java.util.List; + +public class DisenrollmentBeanWrapper { + + private Disenrollment operation; + private List deviceIDs; + + public Disenrollment getOperation() { + return operation; + } + + public void setOperation(Disenrollment operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/EncryptionBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/EncryptionBeanWrapper.java new file mode 100644 index 000000000..462b1137f --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/EncryptionBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.DeviceEncryption; + +import java.util.List; + +/** + * This class is used to wrap the Encrypt bean with devices. + */ +public class EncryptionBeanWrapper { + + private DeviceEncryption operation; + private List deviceIDs; + + public DeviceEncryption getOperation() { + return operation; + } + + public void setOperation(DeviceEncryption operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/LockCodeBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/LockCodeBeanWrapper.java new file mode 100644 index 000000000..41594c280 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/LockCodeBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.LockCode; + +import java.util.List; + +/** + * This class is used to wrap the LockCode bean with devices. + */ +public class LockCodeBeanWrapper { + + private LockCode operation; + private List deviceIDs; + + public LockCode getOperation() { + return operation; + } + + public void setOperation(LockCode operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/NotificationBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/NotificationBeanWrapper.java new file mode 100644 index 000000000..e1092861a --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/NotificationBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.Notification; + +import java.util.List; + +/** + * This class is used to wrap the Notification bean with devices. + */ +public class NotificationBeanWrapper { + + private List deviceIDs; + private Notification operation; + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } + + public Notification getOperation() { + return operation; + } + + public void setOperation(Notification operation) { + this.operation = operation; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/PasswordPolicyBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/PasswordPolicyBeanWrapper.java new file mode 100644 index 000000000..cf54147e0 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/PasswordPolicyBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.PasscodePolicy; + +import java.util.List; + +/** + * This class is used to wrap the PasswordPolicy bean with devices. + */ +public class PasswordPolicyBeanWrapper { + + private PasscodePolicy operation; + private List deviceIDs; + + public PasscodePolicy getOperation() { + return operation; + } + + public void setOperation(PasscodePolicy operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WebClipBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WebClipBeanWrapper.java new file mode 100644 index 000000000..7fbbe8559 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WebClipBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.WebClip; + +import java.util.List; + +/** + * This class is used to wrap the WebClip bean with devices. + */ +public class WebClipBeanWrapper { + + private WebClip operation; + private List deviceIDs; + + public WebClip getOperation() { + return operation; + } + + public void setOperation(WebClip operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WifiBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WifiBeanWrapper.java new file mode 100644 index 000000000..b19e01726 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WifiBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.Wifi; + +import java.util.List; + +/** + * This class is used to wrap the Wifi bean with devices. + */ +public class WifiBeanWrapper { + + private Wifi operation; + private List deviceIDs; + + public Wifi getOperation() { + return operation; + } + + public void setOperation(Wifi operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WipeDataBeanWrapper.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WipeDataBeanWrapper.java new file mode 100644 index 000000000..ebf05d1cd --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WipeDataBeanWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.bean.wrapper; + +import org.wso2.carbon.mdm.services.android.bean.WipeData; + +import java.util.List; + +/** + * This class is used to wrap the WipeData bean with devices. + */ +public class WipeDataBeanWrapper { + + private WipeData operation; + private List deviceIDs; + + public WipeData getOperation() { + return operation; + } + + public void setOperation(WipeData operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorHandler.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorHandler.java new file mode 100644 index 000000000..6d5e0d1c4 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.services.android.common; + +import org.wso2.carbon.mdm.services.android.exception.AndroidAgentException; + +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + + +@Produces({ "application/json", "application/xml" }) +public class ErrorHandler implements ExceptionMapper { + + public Response toResponse(AndroidAgentException exception) { + ErrorMessage errorMessage = new ErrorMessage(); + errorMessage.setErrorMessage(exception.getErrorMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build(); + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorMessage.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorMessage.java new file mode 100644 index 000000000..86be36f36 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorMessage.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.services.android.common; + + +public class ErrorMessage { + + private String errorMessage; + private String errorCode; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/GsonMessageBodyHandler.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/GsonMessageBodyHandler.java new file mode 100644 index 000000000..193eda1bc --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/common/GsonMessageBodyHandler.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.services.android.common; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; + +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +@Provider +@Produces(APPLICATION_JSON) +@Consumes(APPLICATION_JSON) +public class GsonMessageBodyHandler implements MessageBodyWriter, MessageBodyReader { + + private Gson gson; + private static final String UTF_8 = "UTF-8"; + + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return true; + } + + private Gson getGson() { + if (gson == null) { + final GsonBuilder gsonBuilder = new GsonBuilder(); + gson = gsonBuilder.create(); + } + return gson; + } + + public Object readFrom(Class objectClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap stringStringMultivaluedMap, InputStream entityStream) + throws IOException, WebApplicationException { + + InputStreamReader reader = new InputStreamReader(entityStream, "UTF-8"); + + try { + return getGson().fromJson(reader, type); + } finally { + reader.close(); + } + } + + public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return true; + } + + public long getSize(Object o, Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return -1; + } + + public void writeTo(Object object, Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap stringObjectMultivaluedMap, OutputStream entityStream) + throws IOException, WebApplicationException { + + OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8); + try { + Type jsonType; + if (type.equals(type)) { + jsonType = type; + } else { + jsonType = type; + } + getGson().toJson(object, jsonType, writer); + } finally { + writer.close(); + } + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidAgentException.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidAgentException.java new file mode 100644 index 000000000..8698dda76 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidAgentException.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.services.android.exception; + +/** + * + * Custom exception class for Android API related exceptions. + * + */ +public class AndroidAgentException extends Exception{ + + private static final long serialVersionUID = 7950151650447893900L; + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public AndroidAgentException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public AndroidAgentException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public AndroidAgentException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public AndroidAgentException() { + super(); + } + + public AndroidAgentException(Throwable cause) { + super(cause); + } + + + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidOperationException.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidOperationException.java new file mode 100644 index 000000000..d2938a115 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidOperationException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.exception; + +import org.wso2.carbon.mdm.services.android.util.Message; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Custom exception class for wrapping Android Operation related exceptions. + */ +public class AndroidOperationException extends WebApplicationException { + + public AndroidOperationException(Message message, MediaType mediaType) { + super(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(message). + type(mediaType).build()); + } +} + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/BadRequestException.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/BadRequestException.java new file mode 100644 index 000000000..dcf69575e --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/BadRequestException.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.exception; + +import org.wso2.carbon.mdm.services.android.util.Message; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Custom exception class for wrapping BadRequest related exceptions. + */ +public class BadRequestException extends WebApplicationException { + + public BadRequestException(Message message, MediaType mediaType) { + super(Response.status(Response.Status.BAD_REQUEST).entity(message). + type(mediaType).build()); + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/OperationConfigurationException.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/OperationConfigurationException.java new file mode 100644 index 000000000..f0437f9d9 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/exception/OperationConfigurationException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.exception; + +/** + * + * Custom exception class for operation configuration related exceptions. + * + */ +public class OperationConfigurationException extends Exception { + + private static final long serialVersionUID = 7435543643747623629L; + + public OperationConfigurationException(String errorMessage) { + super(errorMessage); + } + + public OperationConfigurationException(String errorMessage, Throwable throwable) { + super(errorMessage, throwable); + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidAPIUtils.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidAPIUtils.java new file mode 100644 index 000000000..2292a3ea2 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidAPIUtils.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.util; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +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.notification.mgt.NotificationManagementService; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.mobile.android.impl.gcm.GCMService; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; + +/** + * AndroidAPIUtil class provides utility functions used by Android REST-API classes. + */ +public class AndroidAPIUtils { + + private static Log log = LogFactory.getLog(AndroidAPIUtils.class); + + public static DeviceIdentifier convertToDeviceIdentifierObject(String deviceId) { + DeviceIdentifier identifier = new DeviceIdentifier(); + identifier.setId(deviceId); + identifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + return identifier; + } + + 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 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static GCMService getGCMService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + GCMService gcmService = (GCMService) ctx.getOSGiService(GCMService.class, null); + if (gcmService == null) { + String msg = "GCM service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return gcmService; + } + + public static MediaType getResponseMediaType(String acceptHeader) { + MediaType responseMediaType; + if (MediaType.WILDCARD.equals(acceptHeader)) { + responseMediaType = MediaType.APPLICATION_JSON_TYPE; + } else { + responseMediaType = MediaType.valueOf(acceptHeader); + } + return responseMediaType; + } + + public static Response getOperationResponse(List deviceIDs, Operation operation, + Message message, MediaType responseMediaType) + throws DeviceManagementException, OperationManagementException { + + AndroidDeviceUtils deviceUtils = new AndroidDeviceUtils(); + DeviceIDHolder deviceIDHolder = deviceUtils.validateDeviceIdentifiers(deviceIDs, + message, responseMediaType); + int status = getDeviceManagementService().addOperation(operation, deviceIDHolder.getValidDeviceIDList()); + if (status > 0) { + GCMService gcmService = getGCMService(); + if (gcmService.isGCMEnabled()) { + List devices = new ArrayList(); + for (DeviceIdentifier deviceIdentifier : deviceIDHolder.getValidDeviceIDList()) { + devices.add(getDeviceManagementService().getDevice(deviceIdentifier)); + } + getGCMService().sendNotification(operation.getCode(), devices); + } + } + if (!deviceIDHolder.getErrorDeviceIdList().isEmpty()) { + return javax.ws.rs.core.Response.status(AndroidConstants.StatusCodes. + MULTI_STATUS_HTTP_CODE).type( + responseMediaType).entity(deviceUtils. + convertErrorMapIntoErrorMessage(deviceIDHolder.getErrorDeviceIdList())).build(); + } + return javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.CREATED). + type(responseMediaType).build(); + } + + + public static PolicyManagerService getPolicyManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + PolicyManagerService policyManagerService = (PolicyManagerService) ctx.getOSGiService( + PolicyManagerService.class, null); + if (policyManagerService == null) { + String msg = "Policy Manager service has not initialized"; + log.error(msg); + throw new IllegalStateException(msg); + } + return policyManagerService; + } + + public static ApplicationManagementProviderService getApplicationManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ApplicationManagementProviderService applicationManagementProviderService = + (ApplicationManagementProviderService) ctx.getOSGiService(ApplicationManagementProviderService.class, null); + if (applicationManagementProviderService == null) { + String msg = "Application Management provider service has not initialized"; + log.error(msg); + throw new IllegalStateException(msg); + } + return applicationManagementProviderService; + } + + public static NotificationManagementService getNotificationManagementService() { + NotificationManagementService notificationManagementService; + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + notificationManagementService = (NotificationManagementService) ctx.getOSGiService( + NotificationManagementService.class, null); + if (notificationManagementService == null) { + String msg = "Notification Management service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return notificationManagementService; + } + + public static void updateOperation(String deviceId, Operation operation) + throws OperationManagementException, PolicyComplianceException, ApplicationManagementException { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + if (AndroidConstants.OperationCodes.MONITOR.equals(operation.getCode())) { + if (log.isDebugEnabled()) { + log.info("Received compliance status from MONITOR operation ID: " + operation.getId()); + } + getPolicyManagerService().checkPolicyCompliance(deviceIdentifier, operation.getOperationResponse()); + } else if (AndroidConstants.OperationCodes.APPLICATION_LIST.equals(operation.getCode())) { + if (log.isDebugEnabled()) { + log.info("Received applications list from device '" + deviceId + "'"); + } + updateApplicationList(operation, deviceIdentifier); + } + getDeviceManagementService().updateOperation(deviceIdentifier, operation); + } + + public static List getPendingOperations + (DeviceIdentifier deviceIdentifier) throws OperationManagementException { + + List operations; + operations = getDeviceManagementService().getPendingOperations(deviceIdentifier); + return operations; + } + + private static void updateApplicationList(Operation operation, DeviceIdentifier deviceIdentifier) + throws ApplicationManagementException { + List applications = new ArrayList(); + // Parsing json string to get applications list. + JsonElement jsonElement = new JsonParser().parse(operation.getOperationResponse()); + JsonArray jsonArray = jsonElement.getAsJsonArray(); + Application app; + for (JsonElement element : jsonArray) { + app = new Application(); + app.setName(element.getAsJsonObject(). + get(AndroidConstants.ApplicationProperties.NAME).getAsString()); + app.setApplicationIdentifier(element.getAsJsonObject(). + get(AndroidConstants.ApplicationProperties.IDENTIFIER).getAsString()); + app.setPlatform(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + applications.add(app); + } + getApplicationManagerService().updateApplicationListInstalledInDevice(deviceIdentifier, applications); + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidConstants.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidConstants.java new file mode 100644 index 000000000..875560de7 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidConstants.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.util; + +/** + * Defines constants used in Android-REST API bundle. + */ +public final class AndroidConstants { + + public final class DeviceProperties{ + private DeviceProperties() { + throw new AssertionError(); + } + public static final String PROPERTY_USER_KEY = "username"; + public static final String PROPERTY_DEVICE_KEY = "device"; + } + + public final class DeviceFeatures{ + private DeviceFeatures() { + throw new AssertionError(); + } + } + + public final class DeviceConstants{ + private DeviceConstants() { + throw new AssertionError(); + } + public static final String DEVICE_MAC_KEY = "mac"; + public static final String DEVICE_DESCRIPTION_KEY = "description"; + public static final String DEVICE_OWNERSHIP_KEY = "ownership"; + public static final String DEVICE_PROPERTIES_KEY = "properties"; + public static final String DEVICE_FEATURES_KEY = "features"; + public static final String DEVICE_DATA = "data"; + public static final String DEVICE_ID_NOT_FOUND = "Device Id not found for device found at %s"; + public static final String DEVICE_ID_SERVICE_NOT_FOUND = + "Issue in retrieving device management service instance for device found at %s"; + } + + public final class Messages{ + private Messages(){ + throw new AssertionError(); + } + public static final String DEVICE_MANAGER_SERVICE_NOT_AVAILABLE = + "Device Manager service not available"; + } + + public final class OperationCodes{ + private OperationCodes(){ + throw new AssertionError(); + } + public static final String DEVICE_LOCK = "DEVICE_LOCK"; + public static final String DEVICE_LOCATION = "DEVICE_LOCATION"; + public static final String WIFI = "WIFI"; + public static final String CAMERA = "CAMERA"; + public static final String DEVICE_MUTE = "DEVICE_MUTE"; + public static final String PASSCODE_POLICY = "PASSCODE_POLICY"; + public static final String DEVICE_INFO = "DEVICE_INFO"; + public static final String ENTERPRISE_WIPE = "ENTERPRISE_WIPE"; + public static final String CLEAR_PASSWORD = "CLEAR_PASSWORD"; + public static final String WIPE_DATA = "WIPE_DATA"; + public static final String APPLICATION_LIST = "APPLICATION_LIST"; + public static final String CHANGE_LOCK_CODE = "CHANGE_LOCK_CODE"; + public static final String INSTALL_APPLICATION = "INSTALL_APPLICATION"; + public static final String UNINSTALL_APPLICATION = "UNINSTALL_APPLICATION"; + public static final String BLACKLIST_APPLICATIONS = "BLACKLIST_APPLICATIONS"; + public static final String ENCRYPT_STORAGE = "ENCRYPT_STORAGE"; + public static final String DEVICE_RING = "DEVICE_RING"; + public static final String NOTIFICATION = "NOTIFICATION"; + public static final String WEBCLIP = "WEBCLIP"; + public static final String DISENROLL = "DISENROLL"; + public static final String MONITOR = "MONITOR"; + } + + public final class StatusCodes{ + private StatusCodes(){ + throw new AssertionError(); + } + public static final int MULTI_STATUS_HTTP_CODE = 207; + } + + public final class TenantConfigProperties{ + private TenantConfigProperties(){ + throw new AssertionError(); + } + public static final String LICENSE_KEY = "androidEula"; + public static final String LANGUAGE_US = "en_US"; + public static final String CONTENT_TYPE_TEXT = "text"; + } + + public final class ApplicationProperties { + private ApplicationProperties(){ + throw new AssertionError(); + } + public static final String NAME = "name"; + public static final String IDENTIFIER = "package"; + public static final String ICON = "icon"; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java new file mode 100644 index 000000000..b41fbd392 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.util; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.device.mgt.common.*; +import org.wso2.carbon.mdm.services.android.exception.BadRequestException; + +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.List; + +/** + * Util class for holding Android device related util methods. + */ +public class AndroidDeviceUtils { + + private static final String COMMA_SEPARATION_PATTERN = ", "; + + public DeviceIDHolder validateDeviceIdentifiers(List deviceIDs, + Message message, MediaType responseMediaType) { + + if (deviceIDs == null || deviceIDs.isEmpty()) { + message.setResponseMessage("Device identifier list is empty"); + throw new BadRequestException(message, responseMediaType); + } + + List errorDeviceIdList = new ArrayList(); + List validDeviceIDList = new ArrayList(); + + int deviceIDCounter = 0; + for (String deviceID : deviceIDs) { + + deviceIDCounter++; + + if (deviceID == null || deviceID.isEmpty()) { + errorDeviceIdList.add(String.format(AndroidConstants.DeviceConstants.DEVICE_ID_NOT_FOUND, + deviceIDCounter)); + continue; + } + + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceID); + deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes. + MOBILE_DEVICE_TYPE_ANDROID); + + if (isValidDeviceIdentifier(deviceIdentifier)) { + validDeviceIDList.add(deviceIdentifier); + } else { + errorDeviceIdList.add(String.format(AndroidConstants.DeviceConstants.DEVICE_ID_NOT_FOUND, + deviceIDCounter)); + } + } catch (DeviceManagementException e) { + errorDeviceIdList.add(String.format(AndroidConstants.DeviceConstants.DEVICE_ID_SERVICE_NOT_FOUND, + deviceIDCounter)); + } + } + + DeviceIDHolder deviceIDHolder = new DeviceIDHolder(); + deviceIDHolder.setValidDeviceIDList(validDeviceIDList); + deviceIDHolder.setErrorDeviceIdList(errorDeviceIdList); + + return deviceIDHolder; + } + + public String convertErrorMapIntoErrorMessage(List errorDeviceIdList) { + return StringUtils.join(errorDeviceIdList.iterator(), COMMA_SEPARATION_PATTERN); + } + + public static boolean isValidDeviceIdentifier(DeviceIdentifier deviceIdentifier) throws DeviceManagementException { + Device device = AndroidAPIUtils.getDeviceManagementService(). + getDevice(deviceIdentifier); + if (device == null || device.getDeviceIdentifier() == null || + device.getDeviceIdentifier().isEmpty() || device.getEnrolmentInfo() == null) { + return false; + } else if (EnrolmentInfo.Status.REMOVED.equals(device.getEnrolmentInfo().getStatus())) { + return false; + } + return true; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/DeviceIDHolder.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/DeviceIDHolder.java new file mode 100644 index 000000000..db8565730 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/DeviceIDHolder.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.util; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; + +import java.util.List; + +/** + * Holder class for storing valid & invalid device-ids. + */ +public class DeviceIDHolder { + + private List errorDeviceIdList; + private List validDeviceIDList; + + public List getErrorDeviceIdList() { + return errorDeviceIdList; + } + + public void setErrorDeviceIdList(List errorDeviceIdList) { + this.errorDeviceIdList = errorDeviceIdList; + } + + public List getValidDeviceIDList() { + return validDeviceIDList; + } + + public void setValidDeviceIDList(List validDeviceIDList) { + this.validDeviceIDList = validDeviceIDList; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/Message.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/Message.java new file mode 100644 index 000000000..d75631001 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/java/org/wso2/carbon/mdm/services/android/util/Message.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.services.android.util; + +import javax.ws.rs.core.MediaType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * This class contains the information of response message. + */ +@XmlRootElement +public class Message { + + private String responseCode; + private String responseMessage; + + @XmlElement + public String getResponseMessage() { + return responseMessage; + } + + public void setResponseMessage(String responseMessage) { + this.responseMessage = responseMessage; + } + + @XmlElement + public String getResponseCode() { + return responseCode; + } + + public void setResponseCode(String responseCode) { + this.responseCode = responseCode; + } + + private Message.MessageBuilder getBuilder() { + return new Message.MessageBuilder(); + } + + public static Message.MessageBuilder responseCode(String responseCode) { + Message message = new Message(); + return message.getBuilder().responseCode(responseCode); + } + + public static Message.MessageBuilder responseMessage(String responseMessage) { + Message message = new Message(); + return message.getBuilder().responseMessage(responseMessage); + } + + public class MessageBuilder { + + private String responseCode; + private String responseMessage; + + public MessageBuilder responseCode(String responseCode) { + this.responseCode = responseCode; + return this; + } + + public MessageBuilder responseMessage(String responseMessage) { + this.responseMessage = responseMessage; + return this; + } + + public Message build() { + Message message = new Message(); + message.setResponseCode(responseCode); + message.setResponseMessage(responseMessage); + return message; + } + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/permissions.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..42478f021 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,315 @@ + + + + + + + + + Get Pending Operation + /device-mgt/android/operations/poll + /operation/* + PUT + emm_android_agent + + + + Lock + /device-mgt/android/operations/lock + /operation/lock + POST + emm_admin,emm_user + + + + Mute + /device-mgt/android/operations/mute + /operation/mute + POST + emm_admin,emm_user + + + + Location + /device-mgt/android/operations/location + /operation/location + POST + emm_admin,emm_user + + + + Clear Passcode + /operation/clear-password/ + POST + emm_admin + + + + Camera + /device-mgt/android/operations/camera + /operation/camera + POST + emm_admin,emm_user + + + + Device Info + /device-mgt/android/operations/device-info + /operation/device-info + POST + emm_admin,emm_user + + + + Enterprise Wipe + /device-mgt/android/operations/enterprise-wipe + /operation/enterprise-wipe + POST + emm_admin + + + + Wipe Data + /device-mgt/android/operations/wipe-data + /operation/wipe-data + POST + emm_admin + + + + Application List + /device-mgt/android/operations/application-list + /operation/application-list + POST + emm_admin,emm_user + + + + Ring + /device-mgt/android/operations/ring-device + /operation/ring-device + POST + emm_admin,emm_user + + + + Install Application + /device-mgt/android/operations/install-application + /operation/install-application + POST + emm_admin,emm_user + + + + Uninstall Application + /device-mgt/android/operations/uninstall-application + /operation/uninstall-application + POST + emm_admin,emm_user + + + + Blacklist Applications + /device-mgt/android/operations/blacklist-applications + /operation/blacklist-applications + POST + emm_admin + + + + Notification + /device-mgt/android/operations/notification + /operation/notification + POST + emm_admin,emm_user + + + + Wifi + /device-mgt/android/operations/wifi + /operation/wifi + POST + emm_admin + + + + Encryption + /device-mgt/android/operations/encrypt + /operation/encrypt + POST + emm_admin + + + + Change lock code + /device-mgt/android/operations/change-lock-code + /operation/change-lock-code + POST + emm_admin + + + + Password Policy + /device-mgt/android/operations/password-policy + /operation/password-policy + POST + emm_admin + + + + Webclip + /device-mgt/android/operations/webclip + /operation/webclip + POST + emm_admin + + + + Disenroll + /device-mgt/android/operations/disenroll + /operation/disenroll + POST + emm_android_agent + + + + + View devices + /device-mgt/android/devices/list + /device + GET + emm_admin + + + + View device + /device-mgt/android/devices/view + /device/* + GET + emm_admin,emm_user + + + + Update device + /device-mgt/android/devices/update + /device/* + PUT + emm_admin,emm_user + + + + Update application list + /device-mgt/android/devices/update-app + /device/appList/* + POST + emm_admin + + + + View license + /device-mgt/android/license/view + /device/license + GET + emm_android_agent + + + + + Enroll device + /device-mgt/android/devices/enroll + /enrollment + POST + emm_android_agent + + + + Get Enrollment Status + /device-mgt/android/devices/enroll + /enrollment/* + GET + emm_android_agent + + + + Update Enrollment + /device-mgt/android/devices/enroll + /enrollment/* + PUT + emm_user,emm_admin + + + + Disenroll device + /device-mgt/android/devices/enroll + /enrollment/* + DELETE + emm_user,emm_admin + + + + + View Policies + /device-mgt/android/policies/view + /policy/* + GET + emm_admin + + + + View Policy Features + /device-mgt/android/policies/view + /policy/features/* + GET + emm_admin + + + + + View Tenant configuration + /device-mgt/android/tenant/configuration + /configuration + GET + emm_admin + + + + Add Tenant configuration + /device-mgt/android/tenant/configuration + /configuration + POST + emm_admin + + + + Update Tenant configuration + /device-mgt/android/tenant/configuration + /configuration + PUT + emm_admin + + \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..46c211bb2 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..cfe04fb73 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/web.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..9e336958f --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,77 @@ + + + + Android-Agent-Webapp + + JAX-WS/JAX-RS MDM Android Endpoint + JAX-WS/JAX-RS Servlet + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + CXFServlet + /* + + + 60 + + + + isAdminService + false + + + managed-api-enabled + false + + + managed-api-owner + admin + + + doAuthentication + true + + + + + + + + + + + + + + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/servicelist.css b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/servicelist.css new file mode 100644 index 000000000..85bc3f613 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/servicelist.css @@ -0,0 +1,117 @@ +@CHARSET "ISO-8859-1"; + +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +html { + background: #efefef; +} + +body { + line-height: 1; + width:960px; + margin:auto; + background:white; + padding:10px; + box-shadow:0px 0px 5px #CCC; + font-family:"Lucida Grande","Lucida Sans","Microsoft Sans Serif", "Lucida Sans Unicode","Verdana","Sans-serif","trebuchet ms" !important; + +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; + width:960px; + border:solid 1px #ccc; +} + +table a { + font-size:12px; + color:#1e90ff; + padding:7px; +float:left; +; +} + +.heading { + font-size: 18px; + margin-top: 20px; + float:left; + color:#0067B1; + margin-bottom:20px; + padding-top:20px; +} + +.field { + font-weight: normal; + width:120px; + font-size:12px; + float:left; + padding:7px; + clear:left; +} +.value { + font-weight: bold; + font-size:12px; + float:left; + padding:7px; + clear:right; +} +.porttypename { + font-weight: bold; + font-size:14px; +} +UL { + margin-top: 0; +} +LI { + font-weight: normal; + font-size:12px; + margin-top:10px; +} + +TD { + border:1px solid #ccc; + vertical-align: text-top; + padding: 5px; +} + + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/pom.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/pom.xml new file mode 100644 index 000000000..15f5e0f91 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/pom.xml @@ -0,0 +1,176 @@ + + + + + + + android-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.android + bundle + WSO2 Carbon - Mobile Device Management Android Impl + WSO2 Carbon - Mobile Device Management Android Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + Device Management Mobile Android Impl Bundle + org.wso2.carbon.device.mgt.mobile.android.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*, + javax.naming, + javax.sql, + javax.xml.bind.annotation.*, + javax.xml.parsers.*;resolution:=optional, + org.w3c.dom, + org.wso2.carbon.core, + org.wso2.carbon.context, + org.wso2.carbon.utils.*, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.mobile.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.policy.mgt.common.*, + org.wso2.carbon.policy.mgt.core.*, + org.wso2.carbon.registry.core, + org.wso2.carbon.registry.core.exceptions, + org.wso2.carbon.registry.core.service, + org.wso2.carbon.registry.core.session, + org.wso2.carbon.registry.api, + org.wso2.carbon.device.mgt.extensions.license.mgt.registry, + com.google.gson.* + + + !org.wso2.carbon.device.mgt.mobile.android.internal, + org.wso2.carbon.device.mgt.mobile.android.* + + + + + + + + + + + + + + + + + + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.carbon + org.wso2.carbon.core + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + org.wso2.carbon + org.wso2.carbon.registry.core + + + org.testng + testng + + + org.apache.tomcat.wso2 + jdbc-pool + + + com.h2database.wso2 + h2-database-engine + test + + + com.google.code.gson + gson + + + diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java new file mode 100644 index 000000000..60c29fec9 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl; + +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; + +/** + * This represents the Android implementation of DeviceManagerService. + */ +public class AndroidDeviceManagementService implements DeviceManagementService { + + private DeviceManager deviceManager; + public static final String DEVICE_TYPE_ANDROID = "android"; + public static final String DEVICE_TYPE_TENANT = "carbon.super"; + + @Override + public String getType() { + return AndroidDeviceManagementService.DEVICE_TYPE_ANDROID; + } + + @Override + public String getProviderTenantDomain() { + return DEVICE_TYPE_TENANT; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public void init() throws DeviceManagementException { + this.deviceManager = new AndroidDeviceManager(); + } + + @Override + public DeviceManager getDeviceManager() { + return deviceManager; + } + + @Override + public ApplicationManager getApplicationManager() { + return null; + } + + @Override + public void notifyOperationToDevices(Operation operation, List deviceIdentifiers) + throws DeviceManagementException { + + } + + @Override + public Application[] getApplications(String s, int i, int i2) throws ApplicationManagementException { + return new Application[0]; + } + + @Override + public void updateApplicationStatus(DeviceIdentifier deviceIdentifier, Application application, + String s) throws ApplicationManagementException { + + } + + @Override + public String getApplicationStatus(DeviceIdentifier deviceIdentifier, + Application application) throws ApplicationManagementException { + return null; + } + + @Override public void installApplicationForDevices(Operation operation, List deviceIdentifiers) + throws ApplicationManagementException { + + } + + @Override public void installApplicationForUsers(Operation operation, List strings) + throws ApplicationManagementException { + + } + + @Override public void installApplicationForUserRoles(Operation operation, List strings) + throws ApplicationManagementException { + + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManager.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManager.java new file mode 100644 index 000000000..e4996c0e4 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManager.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +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 org.wso2.carbon.device.mgt.common.license.mgt.LicenseManager; +import org.wso2.carbon.device.mgt.extensions.license.mgt.registry.RegistryBasedLicenseManager; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.AndroidDAOFactory; +import org.wso2.carbon.device.mgt.mobile.android.impl.util.AndroidPluginUtils; +import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.mobile.common.MobilePluginConstants; +import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dto.MobileDevice; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; +import org.wso2.carbon.registry.api.RegistryException; +import org.wso2.carbon.registry.api.Resource; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import java.io.StringReader; +import java.io.StringWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class AndroidDeviceManager implements DeviceManager { + + private AbstractMobileDeviceManagementDAOFactory daoFactory; + private static final Log log = LogFactory.getLog(AndroidDeviceManagementService.class); + private FeatureManager featureManager = new AndroidFeatureManager(); + private LicenseManager licenseManager; + + public AndroidDeviceManager() { + this.daoFactory = new AndroidDAOFactory(); + this.licenseManager = new RegistryBasedLicenseManager(); + License defaultLicense; + + try { + if (licenseManager.getLicense(AndroidDeviceManagementService.DEVICE_TYPE_ANDROID, + MobilePluginConstants.LANGUAGE_CODE_ENGLISH_US) == null) { + defaultLicense = AndroidPluginUtils.getDefaultLicense(); + licenseManager.addLicense(AndroidDeviceManagementService.DEVICE_TYPE_ANDROID, defaultLicense); + } + featureManager.addSupportedFeaturesToDB(); + } catch (LicenseManagementException e) { + log.error("Error occurred while adding default license for Android devices", e); + } catch (DeviceManagementException e) { + log.error("Error occurred while adding supported device features for Android platform", e); + } + } + + @Override + public FeatureManager getFeatureManager() { + return featureManager; + } + + @Override + public boolean saveConfiguration(TenantConfiguration tenantConfiguration) + throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Persisting android configurations in Registry"); + } + String resourcePath = MobileDeviceManagementUtil.getPlatformConfigPath( + DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + StringWriter writer = new StringWriter(); + JAXBContext context = JAXBContext.newInstance(TenantConfiguration.class); + Marshaller marshaller = context.createMarshaller(); + marshaller.marshal(tenantConfiguration, writer); + + Resource resource = MobileDeviceManagementUtil.getConfigurationRegistry().newResource(); + resource.setContent(writer.toString()); + resource.setMediaType(MobilePluginConstants.MEDIA_TYPE_XML); + MobileDeviceManagementUtil.putRegistryResource(resourcePath, resource); + status = true; + } catch (MobileDeviceMgtPluginException e) { + throw new DeviceManagementException( + "Error occurred while retrieving the Registry instance : " + e.getMessage(), e); + } catch (RegistryException e) { + throw new DeviceManagementException( + "Error occurred while persisting the Registry resource of Android Configuration : " + e.getMessage(), e); + } catch (JAXBException e) { + throw new DeviceManagementException( + "Error occurred while parsing the Android configuration : " + e.getMessage(), e); + } + return status; + } + + @Override + public TenantConfiguration getConfiguration() throws DeviceManagementException { + Resource resource; + try { + String androidRegPath = + MobileDeviceManagementUtil.getPlatformConfigPath(DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + resource = MobileDeviceManagementUtil.getRegistryResource(androidRegPath); + if (resource != null) { + JAXBContext context = JAXBContext.newInstance(TenantConfiguration.class); + Unmarshaller unmarshaller = context.createUnmarshaller(); + return (TenantConfiguration) unmarshaller.unmarshal( + new StringReader(new String((byte[]) resource.getContent(), Charset. + forName(MobilePluginConstants.CHARSET_UTF8)))); + } + return null; + } catch (MobileDeviceMgtPluginException e) { + throw new DeviceManagementException( + "Error occurred while retrieving the Registry instance : " + e.getMessage(), e); + } catch (JAXBException e) { + throw new DeviceManagementException( + "Error occurred while parsing the Android configuration : " + e.getMessage(), e); + } catch (RegistryException e) { + throw new DeviceManagementException( + "Error occurred while retrieving the Registry resource of Android Configuration : " + e.getMessage(), e); + } + } + + @Override + public boolean enrollDevice(Device device) throws DeviceManagementException { + boolean status = false; + MobileDevice mobileDevice = MobileDeviceManagementUtil.convertToMobileDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new Android device : " + device.getDeviceIdentifier()); + } + boolean isEnrolled = this.isEnrolled( + new DeviceIdentifier(device.getDeviceIdentifier(), device.getType())); + if (isEnrolled) { + this.modifyEnrollment(device); + } else { + AndroidDAOFactory.beginTransaction(); + status = daoFactory.getMobileDeviceDAO().addMobileDevice(mobileDevice); + AndroidDAOFactory.commitTransaction(); + } + } catch (MobileDeviceManagementDAOException e) { + try { + AndroidDAOFactory.rollbackTransaction(); + } catch (MobileDeviceManagementDAOException mobileDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + + device.toString(); + log.warn(msg, mobileDAOEx); + } + String msg = + "Error while enrolling the Android device : " + device.getDeviceIdentifier(); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public boolean modifyEnrollment(Device device) throws DeviceManagementException { + boolean status; + MobileDevice mobileDevice = MobileDeviceManagementUtil.convertToMobileDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug("Modifying the Android device enrollment data"); + } + AndroidDAOFactory.beginTransaction(); + status = daoFactory.getMobileDeviceDAO().updateMobileDevice(mobileDevice); + AndroidDAOFactory.commitTransaction(); + } catch (MobileDeviceManagementDAOException e) { + try { + AndroidDAOFactory.rollbackTransaction(); + } catch (MobileDeviceManagementDAOException mobileDAOEx) { + String msg = "Error occurred while roll back the update device transaction :" + + device.toString(); + log.warn(msg, mobileDAOEx); + } + String msg = "Error while updating the enrollment of the Android device : " + + device.getDeviceIdentifier(); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public boolean disenrollDevice(DeviceIdentifier deviceId) throws DeviceManagementException { + //Here we don't have anything specific to do. Hence returning. + return true; + } + + @Override + public boolean isEnrolled(DeviceIdentifier deviceId) throws DeviceManagementException { + boolean isEnrolled = false; + try { + if (log.isDebugEnabled()) { + log.debug("Checking the enrollment of Android device : " + deviceId.getId()); + } + MobileDevice mobileDevice = + daoFactory.getMobileDeviceDAO().getMobileDevice(deviceId.getId()); + if (mobileDevice != null) { + isEnrolled = true; + } + } catch (MobileDeviceManagementDAOException e) { + String msg = "Error while checking the enrollment status of Android device : " + + deviceId.getId(); + 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 Android device : '" + deviceId.getId() + "'"); + } + MobileDevice mobileDevice = daoFactory.getMobileDeviceDAO(). + getMobileDevice(deviceId.getId()); + device = MobileDeviceManagementUtil.convertToDevice(mobileDevice); + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException( + "Error occurred while fetching the Android device: '" + + deviceId.getId() + "'", e); + } + return device; + } + + @Override + public boolean setOwnership(DeviceIdentifier deviceId, String ownershipType) + throws DeviceManagementException { + return true; + } + + @Override + public boolean isClaimable(DeviceIdentifier deviceIdentifier) throws DeviceManagementException { + return false; + } + + @Override + public boolean setStatus(DeviceIdentifier deviceIdentifier, String currentUser, + EnrolmentInfo.Status status) throws DeviceManagementException { + return false; + } + + @Override + public License getLicense(String languageCode) throws LicenseManagementException { + return licenseManager. + getLicense(AndroidDeviceManagementService.DEVICE_TYPE_ANDROID, languageCode); + } + + @Override + public void addLicense(License license) throws LicenseManagementException { + licenseManager.addLicense(AndroidDeviceManagementService.DEVICE_TYPE_ANDROID, license); + } + + @Override + public boolean requireDeviceAuthorization() { + return true; + } + + @Override + public boolean updateDeviceInfo(DeviceIdentifier deviceIdentifier, Device device) + throws DeviceManagementException { + boolean status; + Device existingDevice = this.getDevice(deviceIdentifier); + // This object holds the current persisted device object + MobileDevice existingMobileDevice = + MobileDeviceManagementUtil.convertToMobileDevice(existingDevice); + + // This object holds the newly received device object from response + MobileDevice mobileDevice = MobileDeviceManagementUtil.convertToMobileDevice(device); + + // Updating current object features using newer ones + existingMobileDevice.setLatitude(mobileDevice.getLatitude()); + existingMobileDevice.setLongitude(mobileDevice.getLongitude()); + existingMobileDevice.setDeviceProperties(mobileDevice.getDeviceProperties()); + + try { + if (log.isDebugEnabled()) { + log.debug( + "updating the details of Android device : " + device.getDeviceIdentifier()); + } + AndroidDAOFactory.beginTransaction(); + status = daoFactory.getMobileDeviceDAO().updateMobileDevice(existingMobileDevice); + AndroidDAOFactory.commitTransaction(); + } catch (MobileDeviceManagementDAOException e) { + try { + AndroidDAOFactory.rollbackTransaction(); + } catch (MobileDeviceManagementDAOException e1) { + log.warn("Error occurred while roll back the update device info transaction : '" + + device.toString() + "'", e1); + } + throw new DeviceManagementException( + "Error occurred while updating the Android device: '" + + device.getDeviceIdentifier() + "'", e); + } + return status; + } + + @Override + public List getAllDevices() throws DeviceManagementException { + List devices = null; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Android devices"); + } + List mobileDevices = + daoFactory.getMobileDeviceDAO().getAllMobileDevices(); + if (mobileDevices != null) { + devices = new ArrayList<>(mobileDevices.size()); + for (MobileDevice mobileDevice : mobileDevices) { + devices.add(MobileDeviceManagementUtil.convertToDevice(mobileDevice)); + } + } + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException("Error occurred while fetching all Android devices", + e); + } + return devices; + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidFeatureManager.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidFeatureManager.java new file mode 100644 index 000000000..4649cc63b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidFeatureManager.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.AndroidDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; +import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; + +import java.util.ArrayList; +import java.util.List; + +public class AndroidFeatureManager implements FeatureManager { + + private MobileFeatureDAO featureDAO; + private static final Log log = LogFactory.getLog(AndroidFeatureManager.class); + + public AndroidFeatureManager() { + MobileDeviceManagementDAOFactory daoFactory = new AndroidDAOFactory(); + this.featureDAO = daoFactory.getMobileFeatureDAO(); + } + + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + try { + AndroidDAOFactory.beginTransaction(); + MobileFeature mobileFeature = MobileDeviceManagementUtil.convertToMobileFeature(feature); + featureDAO.addFeature(mobileFeature); + AndroidDAOFactory.commitTransaction(); + return true; + } catch (MobileDeviceManagementDAOException e) { + try { + AndroidDAOFactory.rollbackTransaction(); + } catch (MobileDeviceManagementDAOException e1) { + log.warn("Error occurred while roll-backing the transaction", e); + } + throw new DeviceManagementException("Error occurred while adding the feature", e); + } + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + List mobileFeatures = new ArrayList(features.size()); + for (Feature feature : features) { + mobileFeatures.add(MobileDeviceManagementUtil.convertToMobileFeature(feature)); + } + try { + AndroidDAOFactory.beginTransaction(); + featureDAO.addFeatures(mobileFeatures); + AndroidDAOFactory.commitTransaction(); + return true; + } catch (MobileDeviceManagementDAOException e) { + try { + AndroidDAOFactory.rollbackTransaction(); + } catch (MobileDeviceManagementDAOException e1) { + log.warn("Error occurred while roll-backing the transaction", e); + } + throw new DeviceManagementException("Error occurred while adding the features", e); + } + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + try { + MobileFeature mobileFeature = featureDAO.getFeatureByCode(name); + Feature feature = MobileDeviceManagementUtil.convertToFeature(mobileFeature); + return feature; + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException("Error occurred while retrieving the feature", e); + } + } + + @Override + public List getFeatures() throws DeviceManagementException { + try { + List mobileFeatures = featureDAO.getAllFeatures(); + List featureList = new ArrayList(mobileFeatures.size()); + for (MobileFeature mobileFeature : mobileFeatures) { + featureList.add(MobileDeviceManagementUtil.convertToFeature(mobileFeature)); + } + return featureList; + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException("Error occurred while retrieving the list of features registered for " + + "Android platform", e); + } + } + + @Override + public boolean removeFeature(String code) throws DeviceManagementException { + boolean status; + try { + AndroidDAOFactory.beginTransaction(); + featureDAO.deleteFeatureByCode(code); + AndroidDAOFactory.commitTransaction(); + status = true; + } catch (MobileDeviceManagementDAOException e) { + try { + AndroidDAOFactory.rollbackTransaction(); + } catch (MobileDeviceManagementDAOException e1) { + log.warn("Error occurred while roll-backing the transaction", e); + } + throw new DeviceManagementException("Error occurred while removing the feature", e); + } + return status; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + synchronized (this) { + List supportedFeatures = getSupportedFeatures(); + List existingFeatures = this.getFeatures(); + List missingFeatures = MobileDeviceManagementUtil. + getMissingFeatures(supportedFeatures, existingFeatures); + if (missingFeatures.size() > 0) { + return this.addFeatures(missingFeatures); + } + return true; + } + } + + //Get the supported feature list. + private static List getSupportedFeatures() { + List supportedFeatures = new ArrayList(); + Feature feature = new Feature(); + feature.setCode("DEVICE_LOCK"); + feature.setName("Device Lock"); + feature.setDescription("Lock the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_LOCATION"); + feature.setName("Location"); + feature.setDescription("Request coordinates of device location"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("WIFI"); + feature.setName("wifi"); + feature.setDescription("Setting up wifi configuration"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("CAMERA"); + feature.setName("camera"); + feature.setDescription("Enable or disable camera"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("EMAIL"); + feature.setName("Email"); + feature.setDescription("Configure email settings"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_MUTE"); + feature.setName("mute"); + feature.setDescription("Enable mute in the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_INFO"); + feature.setName("Device info"); + feature.setDescription("Request device information"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("ENTERPRISE_WIPE"); + feature.setName("Enterprise Wipe"); + feature.setDescription("Remove enterprise applications"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("CLEAR_PASSWORD"); + feature.setName("Clear Password"); + feature.setDescription("Clear current password"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("WIPE_DATA"); + feature.setName("Wipe Data"); + feature.setDescription("Factory reset the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("APPLICATION_LIST"); + feature.setName("Application List"); + feature.setDescription("Request list of current installed applications"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("CHANGE_LOCK_CODE"); + feature.setName("Change Lock-code"); + feature.setDescription("Change current lock code"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("INSTALL_APPLICATION"); + feature.setName("Install App"); + feature.setDescription("Install Enterprise or Market application"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("UNINSTALL_APPLICATION"); + feature.setName("Uninstall App"); + feature.setDescription("Uninstall application"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("BLACKLIST_APPLICATIONS"); + feature.setName("Blacklist app"); + feature.setDescription("Blacklist applications"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("ENCRYPT_STORAGE"); + feature.setName("Encrypt storage"); + feature.setDescription("Encrypt storage"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_RING"); + feature.setName("Ring"); + feature.setDescription("Ring the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("PASSCODE_POLICY"); + feature.setName("Password Policy"); + feature.setDescription("Set passcode policy"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("NOTIFICATION"); + feature.setName("Message"); + feature.setDescription("Send message"); + supportedFeatures.add(feature); + return supportedFeatures; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPolicyMonitoringService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPolicyMonitoringService.java new file mode 100644 index 000000000..35c28bd2f --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidPolicyMonitoringService.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.mobile.android.impl.gcm.GCMService; +import org.wso2.carbon.device.mgt.mobile.android.internal.AndroidDeviceManagementDataHolder; +import org.wso2.carbon.policy.mgt.common.Policy; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceData; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceFeature; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; +import org.wso2.carbon.policy.mgt.common.spi.PolicyMonitoringService; + +import java.util.ArrayList; +import java.util.List; + +public class AndroidPolicyMonitoringService implements PolicyMonitoringService { + + private static Log log = LogFactory.getLog(AndroidPolicyMonitoringService.class); + + @Override + public void notifyDevices(List list) throws PolicyComplianceException { + GCMService gcmService = AndroidDeviceManagementDataHolder.getInstance().getGCMService(); + if (gcmService.isGCMEnabled() && !list.isEmpty()) { + gcmService.sendNotification("POLICY_BUNDLE", list); + } + } + + @Override + public ComplianceData checkPolicyCompliance(DeviceIdentifier deviceIdentifier, Policy policy, + Object compliancePayload) throws PolicyComplianceException { + if (log.isDebugEnabled()) { + log.debug("Checking policy compliance status of device '" + deviceIdentifier.getId() + "'"); + } + ComplianceData complianceData = new ComplianceData(); + if (compliancePayload == null || policy == null) { + return complianceData; + } + String compliancePayloadString = new Gson().toJson(compliancePayload); + // Parsing json string to get compliance features. + JsonElement jsonElement; + if (compliancePayloadString instanceof String) { + jsonElement = new JsonParser().parse(compliancePayloadString); + } else { + throw new PolicyComplianceException("Invalid policy compliance payload"); + } + + JsonArray jsonArray = jsonElement.getAsJsonArray(); + Gson gson = new Gson(); + ComplianceFeature complianceFeature; + List complianceFeatures = new ArrayList(jsonArray.size()); + List nonComplianceFeatures = new ArrayList<>(); + + for (JsonElement element : jsonArray) { + complianceFeature = gson.fromJson(element, ComplianceFeature.class); + complianceFeatures.add(complianceFeature); + } + + for (ComplianceFeature cf : complianceFeatures) { + if (!cf.isCompliant()) { + complianceData.setStatus(false); + nonComplianceFeatures.add(cf); + break; + } + } + + complianceData.setComplianceFeatures(nonComplianceFeatures); + return complianceData; + } + + @Override + public String getType() { + return DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidDAOFactory.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidDAOFactory.java new file mode 100644 index 000000000..a2e676acc --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidDAOFactory.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.impl.AndroidDeviceDAOImpl; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.impl.AndroidFeatureDAOImpl; +import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceDAO; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class AndroidDAOFactory extends AbstractMobileDeviceManagementDAOFactory { + + private static final Log log = LogFactory.getLog(AndroidDAOFactory.class); + protected static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal<>(); + + public AndroidDAOFactory() { + this.dataSource = getDataSourceMap().get(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + } + + @Override + public MobileDeviceDAO getMobileDeviceDAO() { + return new AndroidDeviceDAOImpl(); + } + + public MobileFeatureDAO getMobileFeatureDAO() { + return new AndroidFeatureDAOImpl(); + } + + public static void beginTransaction() throws MobileDeviceManagementDAOException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws MobileDeviceManagementDAOException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while retrieving data source connection", + e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws MobileDeviceManagementDAOException { + 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 MobileDeviceManagementDAOException("Error occurred while committing the transaction", e); + } + } + + public static void closeConnection() throws MobileDeviceManagementDAOException { + Connection conn = currentConnection.get(); + try { + if (conn != null) { + conn.close(); + } + } catch (SQLException e) { + log.error("Error occurred while close the connection"); + } + currentConnection.remove(); + } + + public static void rollbackTransaction() throws MobileDeviceManagementDAOException { + 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 MobileDeviceManagementDAOException("Error occurred while rollback the transaction", e); + } + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidFeatureManagementDAOException.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidFeatureManagementDAOException.java new file mode 100644 index 000000000..db218d6df --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/AndroidFeatureManagementDAOException.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.dao; + +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; + +public class AndroidFeatureManagementDAOException extends MobileDeviceManagementDAOException { + + private String message; + private static final long serialVersionUID = 2021891706072918865L; + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message and + * nested exception. + * + * @param message error message + * @param nestedException exception + */ + public AndroidFeatureManagementDAOException(String message, Exception nestedException) { + super(message, nestedException); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message + * and cause. + * + * @param message the detail message. + * @param cause the cause of this exception. + */ + public AndroidFeatureManagementDAOException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message. + * + * @param message the detail message. + */ + public AndroidFeatureManagementDAOException(String message) { + super(message); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified and cause. + * + * @param cause the cause of this exception. + */ + public AndroidFeatureManagementDAOException(Throwable cause) { + super(cause); + } + + public String getMessage() { + return message; + } + + public void setErrorMessage(String errorMessage) { + this.message = errorMessage; + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidDeviceDAOImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidDeviceDAOImpl.java new file mode 100644 index 000000000..0d831901d --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidDeviceDAOImpl.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.AndroidDAOFactory; +import org.wso2.carbon.device.mgt.mobile.android.impl.util.AndroidPluginConstants; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceDAO; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.mobile.dto.MobileDevice; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implements MobileDeviceDAO for Android Devices. + */ +public class AndroidDeviceDAOImpl implements MobileDeviceDAO{ + + private static final Log log = LogFactory.getLog(AndroidDeviceDAOImpl.class); + + @Override + public MobileDevice getMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + MobileDevice mobileDevice = null; + ResultSet rs = null; + try { + conn = AndroidDAOFactory.getConnection(); + String selectDBQuery = + "SELECT DEVICE_ID, GCM_TOKEN, DEVICE_INFO, DEVICE_MODEL, SERIAL, " + + "VENDOR, MAC_ADDRESS, DEVICE_NAME, LATITUDE, LONGITUDE, IMEI, IMSI, OS_VERSION" + + " FROM AD_DEVICE WHERE DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, mblDeviceId); + rs = stmt.executeQuery(); + + if (rs.next()) { + mobileDevice = new MobileDevice(); + mobileDevice.setMobileDeviceId(rs.getString(AndroidPluginConstants.DEVICE_ID)); + mobileDevice.setModel(rs.getString(AndroidPluginConstants.DEVICE_MODEL)); + mobileDevice.setSerial(rs.getString(AndroidPluginConstants.SERIAL)); + mobileDevice.setVendor(rs.getString(AndroidPluginConstants.VENDOR)); + mobileDevice.setLatitude(rs.getString(AndroidPluginConstants.LATITUDE)); + mobileDevice.setLongitude(rs.getString(AndroidPluginConstants.LONGITUDE)); + mobileDevice.setImei(rs.getString(AndroidPluginConstants.IMEI)); + mobileDevice.setImsi(rs.getString(AndroidPluginConstants.IMSI)); + mobileDevice.setOsVersion(rs.getString(AndroidPluginConstants.OS_VERSION)); + + Map propertyMap = new HashMap(); + propertyMap.put(AndroidPluginConstants.GCM_TOKEN, rs.getString(AndroidPluginConstants.GCM_TOKEN)); + propertyMap.put(AndroidPluginConstants.DEVICE_INFO, rs.getString(AndroidPluginConstants.DEVICE_INFO)); + propertyMap.put(AndroidPluginConstants.DEVICE_NAME, rs.getString(AndroidPluginConstants.DEVICE_NAME)); + mobileDevice.setDeviceProperties(propertyMap); + + if (log.isDebugEnabled()) { + log.debug("Android device " + mblDeviceId + " data has been fetched from " + + "Android database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Android device : '" + mblDeviceId + "'"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + AndroidDAOFactory.closeConnection(); + } + + return mobileDevice; + } + + @Override + public boolean addMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = AndroidDAOFactory.getConnection(); + String createDBQuery = + "INSERT INTO AD_DEVICE(DEVICE_ID, GCM_TOKEN, DEVICE_INFO, SERIAL, " + + "VENDOR, MAC_ADDRESS, DEVICE_NAME, LATITUDE, LONGITUDE, IMEI, IMSI, " + + "OS_VERSION, DEVICE_MODEL) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, mobileDevice.getMobileDeviceId()); + + Map properties = mobileDevice.getDeviceProperties(); + stmt.setString(2, properties.get(AndroidPluginConstants.GCM_TOKEN)); + stmt.setString(3, properties.get(AndroidPluginConstants.DEVICE_INFO)); + stmt.setString(4, mobileDevice.getSerial()); + stmt.setString(5, mobileDevice.getVendor()); + stmt.setString(6, mobileDevice.getMobileDeviceId()); + stmt.setString(7, properties.get(AndroidPluginConstants.DEVICE_NAME)); + stmt.setString(8, mobileDevice.getLongitude()); + stmt.setString(9, mobileDevice.getLongitude()); + stmt.setString(10, mobileDevice.getImei()); + stmt.setString(11, mobileDevice.getImsi()); + stmt.setString(12, mobileDevice.getOsVersion()); + stmt.setString(13, mobileDevice.getModel()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android device " + mobileDevice.getMobileDeviceId() + " data has been" + + " added to the Android database."); + } + } + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while adding the Android device '" + + mobileDevice.getMobileDeviceId() + "' information to the Android plugin data store.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean updateMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = AndroidDAOFactory.getConnection(); + String updateDBQuery = + "UPDATE AD_DEVICE SET GCM_TOKEN = ?, DEVICE_INFO = ?, SERIAL = ?, VENDOR = ?, " + + "MAC_ADDRESS = ?, DEVICE_NAME = ?, LATITUDE = ?, LONGITUDE = ?, IMEI = ?, " + + "IMSI = ?, OS_VERSION = ?, DEVICE_MODEL = ? WHERE DEVICE_ID = ?"; + stmt = conn.prepareStatement(updateDBQuery); + + Map properties = mobileDevice.getDeviceProperties(); + stmt.setString(1, properties.get(AndroidPluginConstants.GCM_TOKEN)); + stmt.setString(2, properties.get(AndroidPluginConstants.DEVICE_INFO)); + stmt.setString(3, mobileDevice.getSerial()); + stmt.setString(4, mobileDevice.getVendor()); + stmt.setString(5, mobileDevice.getMobileDeviceId()); + stmt.setString(6, properties.get(AndroidPluginConstants.DEVICE_NAME)); + stmt.setString(7, mobileDevice.getLatitude()); + stmt.setString(8, mobileDevice.getLongitude()); + stmt.setString(9, mobileDevice.getImei()); + stmt.setString(10, mobileDevice.getImsi()); + stmt.setString(11, mobileDevice.getOsVersion()); + stmt.setString(12, mobileDevice.getModel()); + stmt.setString(13, mobileDevice.getMobileDeviceId()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android device " + mobileDevice.getMobileDeviceId() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Android device '" + + mobileDevice.getMobileDeviceId() + "' data."; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteMobileDevice(String mblDeviceId) + throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = AndroidDAOFactory.getConnection(); + String deleteDBQuery = + "DELETE FROM AD_DEVICE WHERE DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, mblDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android device " + mblDeviceId + " data has deleted" + + " from the Android database."); + } + } + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while deleting android device '" + + mblDeviceId + "'", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public List getAllMobileDevices() throws MobileDeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + MobileDevice mobileDevice; + List mobileDevices = new ArrayList(); + try { + conn = AndroidDAOFactory.getConnection(); + String selectDBQuery = + "SELECT DEVICE_ID, GCM_TOKEN, DEVICE_INFO, DEVICE_MODEL, SERIAL, " + + "VENDOR, MAC_ADDRESS, DEVICE_NAME, LATITUDE, LONGITUDE, IMEI, IMSI, OS_VERSION " + + "FROM AD_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + rs = stmt.executeQuery(); + + while (rs.next()) { + mobileDevice = new MobileDevice(); + mobileDevice.setMobileDeviceId(rs.getString(AndroidPluginConstants.DEVICE_ID)); + mobileDevice.setModel(rs.getString(AndroidPluginConstants.DEVICE_MODEL)); + mobileDevice.setSerial(rs.getString(AndroidPluginConstants.SERIAL)); + mobileDevice.setVendor(rs.getString(AndroidPluginConstants.VENDOR)); + mobileDevice.setLatitude(rs.getString(AndroidPluginConstants.LATITUDE)); + mobileDevice.setLongitude(rs.getString(AndroidPluginConstants.LONGITUDE)); + mobileDevice.setImei(rs.getString(AndroidPluginConstants.IMEI)); + mobileDevice.setImsi(rs.getString(AndroidPluginConstants.IMSI)); + mobileDevice.setOsVersion(rs.getString(AndroidPluginConstants.OS_VERSION)); + + Map propertyMap = new HashMap<>(); + propertyMap.put(AndroidPluginConstants.GCM_TOKEN, rs.getString(AndroidPluginConstants.GCM_TOKEN)); + propertyMap.put(AndroidPluginConstants.DEVICE_INFO, rs.getString(AndroidPluginConstants.DEVICE_INFO)); + propertyMap.put(AndroidPluginConstants.DEVICE_NAME, rs.getString(AndroidPluginConstants.DEVICE_NAME)); + mobileDevice.setDeviceProperties(propertyMap); + + mobileDevices.add(mobileDevice); + } + if (log.isDebugEnabled()) { + log.debug("All Android device details have fetched from Android database."); + } + return mobileDevices; + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while fetching all Android device data", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + AndroidDAOFactory.closeConnection(); + } + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidFeatureDAOImpl.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidFeatureDAOImpl.java new file mode 100644 index 000000000..072a54c9e --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/dao/impl/AndroidFeatureDAOImpl.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.AndroidDAOFactory; +import org.wso2.carbon.device.mgt.mobile.android.impl.dao.AndroidFeatureManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.android.impl.util.AndroidPluginConstants; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class AndroidFeatureDAOImpl implements MobileFeatureDAO { + + private static final Log log = LogFactory.getLog(AndroidFeatureDAOImpl.class); + + public AndroidFeatureDAOImpl() { + + } + + @Override + public boolean addFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + boolean status = false; + Connection conn; + try { + conn = AndroidDAOFactory.getConnection(); + String sql = "INSERT INTO AD_FEATURE(CODE, NAME, DESCRIPTION) VALUES (?, ?, ?)"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, mobileFeature.getCode()); + stmt.setString(2, mobileFeature.getName()); + stmt.setString(3, mobileFeature.getDescription()); + stmt.executeUpdate(); + status = true; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException( + "Error occurred while adding android feature '" + + mobileFeature.getName() + "' into the metadata repository", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean addFeatures(List mobileFeatures) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + MobileFeature mobileFeature; + boolean status = false; + Connection conn; + try { + conn = AndroidDAOFactory.getConnection(); + stmt = conn.prepareStatement("INSERT INTO AD_FEATURE(CODE, NAME, DESCRIPTION) VALUES (?, ?, ?)"); + for (int i = 0; i < mobileFeatures.size(); i++) { + mobileFeature = mobileFeatures.get(i); + stmt.setString(1, mobileFeature.getCode()); + stmt.setString(2, mobileFeature.getName()); + stmt.setString(3, mobileFeature.getDescription()); + stmt.addBatch(); + } + stmt.executeBatch(); + status = true; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException( + "Error occurred while adding android features into the metadata repository", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean updateFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = AndroidDAOFactory.getConnection(); + String updateDBQuery = + "UPDATE AD_FEATURE SET NAME = ?, DESCRIPTION = ?" + + "WHERE CODE = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, mobileFeature.getName()); + stmt.setString(2, mobileFeature.getDescription()); + stmt.setString(3, mobileFeature.getCode()); + + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Android Feature " + mobileFeature.getCode() + " data has been " + + "modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while updating the Android Feature '" + + mobileFeature.getCode() + "' to the Android db."; + log.error(msg, e); + throw new AndroidFeatureManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException { + + PreparedStatement stmt = null; + boolean status = false; + Connection conn; + try { + conn = AndroidDAOFactory.getConnection(); + String sql = "DELETE FROM AD_FEATURE WHERE ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, mblFeatureId); + stmt.execute(); + status = true; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException( + "Error occurred while deleting android feature '" + + mblFeatureId + "' from Android database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + boolean status = false; + Connection conn; + try { + conn = AndroidDAOFactory.getConnection(); + String sql = "DELETE FROM AD_FEATURE WHERE CODE = ?"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, mblFeatureCode); + stmt.execute(); + status = true; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException( + "Error occurred while deleting android feature '" + + mblFeatureCode + "' from Android database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public MobileFeature getFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn; + try { + conn = AndroidDAOFactory.getConnection(); + String sql = "SELECT ID, CODE, NAME, DESCRIPTION FROM AD_FEATURE WHERE ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, mblFeatureId); + rs = stmt.executeQuery(); + + MobileFeature mobileFeature = null; + if (rs.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(rs.getInt(AndroidPluginConstants.ANDROID_FEATURE_ID)); + mobileFeature.setCode(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_CODE)); + mobileFeature.setName(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_NAME)); + mobileFeature.setDescription(rs.getString(AndroidPluginConstants. + ANDROID_FEATURE_DESCRIPTION)); + mobileFeature.setDeviceType( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + } + return mobileFeature; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException( + "Error occurred while retrieving android feature '" + + mblFeatureId + "' from the Android database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + AndroidDAOFactory.closeConnection(); + } + } + + @Override + public MobileFeature getFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn; + + try { + conn = AndroidDAOFactory.getConnection(); + String sql = "SELECT ID, CODE, NAME, DESCRIPTION FROM AD_FEATURE WHERE CODE = ?"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, mblFeatureCode); + rs = stmt.executeQuery(); + + MobileFeature mobileFeature = null; + if (rs.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(rs.getInt(AndroidPluginConstants.ANDROID_FEATURE_ID)); + mobileFeature.setCode(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_CODE)); + mobileFeature.setName(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_NAME)); + mobileFeature.setDescription(rs.getString(AndroidPluginConstants. + ANDROID_FEATURE_DESCRIPTION)); + mobileFeature.setDeviceType( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + } + return mobileFeature; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException( + "Error occurred while retrieving android feature '" + + mblFeatureCode + "' from the Android database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + AndroidDAOFactory.closeConnection(); + } + } + + @Override + public List getFeatureByDeviceType(String deviceType) + throws MobileDeviceManagementDAOException { + return this.getAllFeatures(); + } + + @Override + public List getAllFeatures() throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn = null; + List features = new ArrayList<>(); + try { + conn = AndroidDAOFactory.getConnection(); + String sql = "SELECT ID, CODE, NAME, DESCRIPTION FROM AD_FEATURE"; + stmt = conn.prepareStatement(sql); + rs = stmt.executeQuery(); + MobileFeature mobileFeature = null; + + while (rs.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(rs.getInt(AndroidPluginConstants.ANDROID_FEATURE_ID)); + mobileFeature.setCode(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_CODE)); + mobileFeature.setName(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_NAME)); + mobileFeature.setDescription(rs.getString(AndroidPluginConstants.ANDROID_FEATURE_DESCRIPTION)); + mobileFeature.setDeviceType( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID); + features.add(mobileFeature); + } + return features; + } catch (SQLException e) { + throw new AndroidFeatureManagementDAOException("Error occurred while retrieving all " + + "android features from the android database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + AndroidDAOFactory.closeConnection(); + } + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMResult.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMResult.java new file mode 100644 index 000000000..f9c770358 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMResult.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.gcm; + +/** + * Represents model object for holding GCM response data. + */ +public class GCMResult { + + private String errorMsg; + private String msg; + private int statusCode; + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMService.java new file mode 100644 index 000000000..bfa1685fa --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMService.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.gcm; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; + +import java.util.ArrayList; +import java.util.List; + +/** + * GCM notification service implementation for Android platform. + */ +public class GCMService { + + private static final Log log = LogFactory.getLog(GCMService.class); + private static final String NOTIFIER_TYPE = "notifierType"; + private static final String GCM_NOTIFIER_CODE = "2"; + + public boolean isGCMEnabled() { + String notifierType = GCMUtil.getConfigurationProperty(NOTIFIER_TYPE); + if (GCM_NOTIFIER_CODE.equals(notifierType)) { + return true; + } + return false; + } + + public void sendNotification(String messageData, Device device) { + List devices = new ArrayList<>(1); + devices.add(device); + GCMResult result = GCMUtil.sendWakeUpCall(messageData, devices); + if (result.getStatusCode() != 200) { + log.error("Exception occurred while sending the GCM notification : " + result.getErrorMsg()); + } + } + + public void sendNotification(String messageData, List devices) { + GCMResult result = GCMUtil.sendWakeUpCall(messageData, devices); + if (result.getStatusCode() != 200) { + log.error("Exception occurred while sending the GCM notification : " + result.getErrorMsg()); + } + } + + public void resetTenantConfigCache() { + GCMUtil.resetTenantConfigCache(); + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMUtil.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMUtil.java new file mode 100644 index 000000000..ba41698e8 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/gcm/GCMUtil.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.gcm; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.android.impl.util.AndroidPluginConstants; +import org.wso2.carbon.device.mgt.mobile.android.internal.AndroidDeviceManagementDataHolder; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Implements utility methods used by GCMService. + */ +public class GCMUtil { + + private static final Log log = LogFactory.getLog(GCMService.class); + + private final static String GCM_ENDPOINT = "https://gcm-http.googleapis.com/gcm/send"; + private static final String GCM_API_KEY = "gcmAPIKey"; + private static final int TIME_TO_LIVE = 60; + private static final int HTTP_STATUS_CODE_OK = 200; + + private static HashMap tenantConfigurationCache = new HashMap<>(); + + public static GCMResult sendWakeUpCall(String message, List devices) { + GCMResult result = new GCMResult(); + + byte[] bytes = getGCMRequest(message, getGCMTokens(devices)).getBytes(); + HttpURLConnection conn; + try { + conn = (HttpURLConnection) (new URL(GCM_ENDPOINT)).openConnection(); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setFixedLengthStreamingMode(bytes.length); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json"); + conn.setRequestProperty("Authorization", "key=" + getConfigurationProperty(GCM_API_KEY)); + + OutputStream out = conn.getOutputStream(); + out.write(bytes); + out.close(); + + int status = conn.getResponseCode(); + result.setStatusCode(status); + if (status != HTTP_STATUS_CODE_OK) { + result.setErrorMsg(getString(conn.getErrorStream())); + } else { + result.setMsg(getString(conn.getInputStream())); + } + } catch (ProtocolException e) { + log.error("Exception occurred while setting the HTTP protocol.", e); + } catch (IOException ex) { + log.error("Exception occurred while sending the GCM request.", ex); + } + + return result; + } + + private static String getString(InputStream stream) throws IOException { + if (stream != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + StringBuilder content = new StringBuilder(); + + String newLine; + do { + newLine = reader.readLine(); + if (newLine != null) { + content.append(newLine).append('\n'); + } + } while (newLine != null); + + if (content.length() > 0) { + content.setLength(content.length() - 1); + } + + return content.toString(); + } + return null; + } + + private static String getGCMRequest(String message, List registrationIds) { + JsonObject gcmRequest = new JsonObject(); + gcmRequest.addProperty("delay_while_idle", false); + gcmRequest.addProperty("time_to_live", TIME_TO_LIVE); + + //Add message to GCM request + JsonObject data = new JsonObject(); + if (message != null && !message.isEmpty()) { + data.addProperty("data", message); + gcmRequest.add("data", data); + } + + //Set device reg-ids + JsonArray regIds = new JsonArray(); + for (String regId : registrationIds) { + if (regId == null || regId.isEmpty()) { + continue; + } + regIds.add(new JsonPrimitive(regId)); + } + + gcmRequest.add("registration_ids", regIds); + return gcmRequest.toString(); + } + + private static List getGCMTokens(List devices) { + List tokens = new ArrayList<>(devices.size()); + for (Device device : devices) { + tokens.add(getGCMToken(device.getProperties())); + } + return tokens; + } + + private static String getGCMToken(List properties) { + String gcmToken = null; + for (Device.Property property : properties) { + if (AndroidPluginConstants.GCM_TOKEN.equals(property.getName())) { + gcmToken = property.getValue(); + break; + } + } + return gcmToken; + } + + public static String getConfigurationProperty(String property) { + DeviceManagementService androidDMService = AndroidDeviceManagementDataHolder.getInstance(). + getAndroidDeviceManagementService(); + try { + //Get the TenantConfiguration from cache if not we'll get it from DM service + TenantConfiguration tenantConfiguration = getTenantConfigurationFromCache(); + if (tenantConfiguration == null) { + tenantConfiguration = androidDMService.getDeviceManager().getConfiguration(); + if (tenantConfiguration != null) { + addTenantConfigurationToCache(tenantConfiguration); + } + } + + if (tenantConfiguration != null) { + List configs = tenantConfiguration.getConfiguration(); + for (ConfigurationEntry entry : configs) { + if (property.equals(entry.getName())) { + return (String) entry.getValue(); + } + } + } + return ""; + } catch (DeviceManagementException e) { + log.error("Exception occurred while fetching the tenant-config.",e); + } + return null; + } + + public static void resetTenantConfigCache() { + tenantConfigurationCache.remove(getTenantId()); + } + + private static void addTenantConfigurationToCache(TenantConfiguration tenantConfiguration) { + tenantConfigurationCache.put(getTenantId(), tenantConfiguration); + } + + private static TenantConfiguration getTenantConfigurationFromCache() { + return tenantConfigurationCache.get(getTenantId()); + } + + private static int getTenantId() { + return CarbonContext.getThreadLocalCarbonContext().getTenantId(); + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginConstants.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginConstants.java new file mode 100644 index 000000000..7f6386210 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginConstants.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.util; + +/** + * Defines constants used by android plugin. + */ +public class AndroidPluginConstants { + + //Properties related to AD_DEVICE table + public static final String DEVICE_ID = "DEVICE_ID"; + public static final String GCM_TOKEN = "GCM_TOKEN"; + public static final String DEVICE_INFO = "DEVICE_INFO"; + public static final String SERIAL = "SERIAL"; + public static final String DEVICE_MODEL = "DEVICE_MODEL"; + public static final String DEVICE_NAME = "DEVICE_NAME"; + public static final String LATITUDE = "LATITUDE"; + public static final String LONGITUDE = "LONGITUDE"; + public static final String IMEI = "IMEI"; + public static final String IMSI = "IMSI"; + public static final String VENDOR = "VENDOR"; + public static final String OS_VERSION = "OS_VERSION"; + public static final String MAC_ADDRESS = "MAC_ADDRESS"; + + //Properties related to AD_FEATURE table + public static final String ANDROID_FEATURE_ID = "ID"; + public static final String ANDROID_FEATURE_CODE = "CODE"; + public static final String ANDROID_FEATURE_NAME = "NAME"; + public static final String ANDROID_FEATURE_DESCRIPTION = "DESCRIPTION"; + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginUtils.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginUtils.java new file mode 100644 index 000000000..40ea3c18b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidPluginUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.util; + +import org.wso2.carbon.device.mgt.common.license.mgt.License; +import org.wso2.carbon.device.mgt.mobile.android.impl.AndroidDeviceManagementService; + +/** + * Contains utility methods used by Android plugin. + */ +public class AndroidPluginUtils { + + public static License getDefaultLicense() { + License license = new License(); + license.setName(AndroidDeviceManagementService.DEVICE_TYPE_ANDROID); + license.setLanguage("en_US"); + license.setVersion("1.0.0"); + license.setText("This End User License Agreement (\"Agreement\") is a legal agreement between you (\"You\") " + + "and WSO2, Inc., regarding the enrollment of Your personal mobile device (\"Device\") in SoR's " + + "mobile device management program, and the loading to and removal from Your Device and Your use " + + "of certain applications and any associated software and user documentation, whether provided in " + + "\"online\" or electronic format, used in connection with the operation of or provision of services " + + "to WSO2, Inc., BY SELECTING \"I ACCEPT\" DURING INSTALLATION, YOU ARE ENROLLING YOUR DEVICE, AND " + + "THEREBY AUTHORIZING SOR OR ITS AGENTS TO INSTALL, UPDATE AND REMOVE THE APPS FROM YOUR DEVICE AS " + + "DESCRIBED IN THIS AGREEMENT. YOU ARE ALSO EXPLICITLY ACKNOWLEDGING AND AGREEING THAT (1) THIS IS " + + "A BINDING CONTRACT AND (2) YOU HAVE READ AND AGREE TO THE TERMS OF THIS AGREEMENT.\n" + + "\n" + + "IF YOU DO NOT ACCEPT THESE TERMS, DO NOT ENROLL YOUR DEVICE AND DO NOT PROCEED ANY FURTHER.\n" + + "\n" + + "You agree that: (1) You understand and agree to be bound by the terms and conditions contained " + + "in this Agreement, and (2) You are at least 21 years old and have the legal capacity to enter " + + "into this Agreement as defined by the laws of Your jurisdiction. SoR shall have the right, " + + "without prior notice, to terminate or suspend (i) this Agreement, (ii) the enrollment of Your " + + "Device, or (iii) the functioning of the Apps in the event of a violation of this Agreement or " + + "the cessation of Your relationship with SoR (including termination of Your employment if You are " + + "an employee or expiration or termination of Your applicable franchise or supply agreement if You " + + "are a franchisee of or supplier to the WSO2 WSO2, Inc., system). SoR expressly reserves all " + + "rights not expressly granted herein."); + return license; + } + +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidUtils.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidUtils.java new file mode 100644 index 000000000..583a6cef0 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/util/AndroidUtils.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.impl.util; + +import java.util.Map; + +/** + * Contains utility methods used by Android plugin. + */ +public class AndroidUtils { + + public static String getDeviceProperty(Map deviceProperties, String property) { + return deviceProperties.get(property); + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementDataHolder.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementDataHolder.java new file mode 100644 index 000000000..ee4a7c021 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementDataHolder.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.internal; + +import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.android.impl.gcm.GCMService; +import org.wso2.carbon.registry.core.service.RegistryService; + +/** + * DataHolder class of Mobile plugins component. + */ +public class AndroidDeviceManagementDataHolder { + + private RegistryService registryService; + private DeviceManagementService androidDeviceManagementService; + private GCMService gcmService; + + private static AndroidDeviceManagementDataHolder thisInstance = new AndroidDeviceManagementDataHolder(); + + private AndroidDeviceManagementDataHolder() { + } + + public static AndroidDeviceManagementDataHolder getInstance() { + return thisInstance; + } + + public RegistryService getRegistryService() { + return registryService; + } + + public void setRegistryService(RegistryService registryService) { + this.registryService = registryService; + } + + public DeviceManagementService getAndroidDeviceManagementService() { + return androidDeviceManagementService; + } + + public void setAndroidDeviceManagementService( + DeviceManagementService androidDeviceManagementService) { + this.androidDeviceManagementService = androidDeviceManagementService; + } + + public GCMService getGCMService() { + return gcmService; + } + + public void setGCMService(GCMService gcmService) { + this.gcmService = gcmService; + } +} diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementServiceComponent.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementServiceComponent.java new file mode 100644 index 000000000..7eea7f814 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/internal/AndroidDeviceManagementServiceComponent.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.android.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.mobile.android.impl.AndroidDeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.android.impl.AndroidPolicyMonitoringService; +import org.wso2.carbon.device.mgt.mobile.android.impl.gcm.GCMService; +import org.wso2.carbon.device.mgt.mobile.internal.MobileDeviceManagementDataHolder; +import org.wso2.carbon.ndatasource.core.DataSourceService; +import org.wso2.carbon.policy.mgt.common.spi.PolicyMonitoringService; +import org.wso2.carbon.registry.core.service.RegistryService; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.mobile.android.impl.internal.AndroidDeviceManagementServiceComponent" + * immediate="true" + * @scr.reference name="org.wso2.carbon.ndatasource" + * interface="org.wso2.carbon.ndatasource.core.DataSourceService" + * cardinality="1..1" + * policy="dynamic" + * bind="setDataSourceService" + * unbind="unsetDataSourceService" + * @scr.reference name="registry.service" + * interface="org.wso2.carbon.registry.core.service.RegistryService" cardinality="0..1" + * policy="dynamic" bind="setRegistryService" unbind="unsetRegistryService" + *

      + * Adding reference to API Manager Configuration service is an unavoidable hack to get rid of NPEs thrown while + * initializing APIMgtDAOs attempting to register APIs programmatically. APIMgtDAO needs to be proper cleaned up + * to avoid as an ideal fix + */ +public class AndroidDeviceManagementServiceComponent { + + private static final Log log = LogFactory.getLog(AndroidDeviceManagementServiceComponent.class); + private ServiceRegistration androidServiceRegRef; + private ServiceRegistration gcmServiceRegRef; + + protected void activate(ComponentContext ctx) { + + if (log.isDebugEnabled()) { + log.debug("Activating Android Mobile Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + + DeviceManagementService androidDeviceManagementService = new AndroidDeviceManagementService(); + GCMService gcmService = new GCMService(); + + androidServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + androidDeviceManagementService, null); + + gcmServiceRegRef = + bundleContext.registerService(GCMService.class.getName(), gcmService, null); + + + // Policy management service + + bundleContext.registerService(PolicyMonitoringService.class, + new AndroidPolicyMonitoringService(), null); + + AndroidDeviceManagementDataHolder.getInstance().setAndroidDeviceManagementService( + androidDeviceManagementService); + AndroidDeviceManagementDataHolder.getInstance().setGCMService(gcmService); + + if (log.isDebugEnabled()) { + log.debug("Android Mobile Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Android Mobile Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Android Mobile Device Management Service Component"); + } + try { + if (androidServiceRegRef != null) { + androidServiceRegRef.unregister(); + } + if (gcmServiceRegRef != null) { + gcmServiceRegRef.unregister(); + } + if (log.isDebugEnabled()) { + log.debug( + "Android Mobile Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Android Mobile Device Management bundle", e); + } + } + + protected void setDataSourceService(DataSourceService dataSourceService) { + /* This is to avoid mobile device management component getting initialized before the underlying datasources + are registered */ + if (log.isDebugEnabled()) { + log.debug("Data source service set to android mobile service component"); + } + } + + protected void unsetDataSourceService(DataSourceService dataSourceService) { + //do nothing + } + + protected void setRegistryService(RegistryService registryService) { + if (log.isDebugEnabled()) { + log.debug("RegistryService acquired"); + } + AndroidDeviceManagementDataHolder.getInstance().setRegistryService(registryService); + } + + protected void unsetRegistryService(RegistryService registryService) { + AndroidDeviceManagementDataHolder.getInstance().setRegistryService(null); + } + +} diff --git a/components/mobile-plugins/android-plugin/pom.xml b/components/mobile-plugins/android-plugin/pom.xml new file mode 100644 index 000000000..0dbcdff77 --- /dev/null +++ b/components/mobile-plugins/android-plugin/pom.xml @@ -0,0 +1,59 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + mobile-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + android-plugin + pom + WSO2 Carbon - Mobile Plugins + http://wso2.org + + + org.wso2.carbon.device.mgt.mobile.android + org.wso2.carbon.device.mgt.mobile.android.agent + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml new file mode 100644 index 000000000..bd997683e --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml @@ -0,0 +1,205 @@ + + + + + + + mobile-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.api + war + WSO2 Carbon - Mobile Device Management API + WSO2 Carbon - Mobile Device Management API + http://wso2.org + + + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + maven-war-plugin + 2.2 + + WEB-INF/lib/*cxf*.jar + ${project.artifactId} + + + + + + + + deploy + + compile + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + compile + + run + + + + + + + + + + + + + + + + + + + client + + test + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + test + + java + + + + + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-frontend-jaxrs + + + org.apache.cxf + cxf-rt-transports-http + + + junit + junit + test + + + commons-httpclient.wso2 + commons-httpclient + provided + + + javax.ws.rs + jsr311-api + provided + + + org.wso2.carbon + org.wso2.carbon.utils + provided + + + org.wso2.carbon.commons + org.wso2.carbon.user.mgt + provided + + + org.wso2.carbon + org.wso2.carbon.logging + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth.stub + provided + + + org.apache.axis2.wso2 + axis2-client + + + + + com.google.code.gson + gson + + + commons-codec.wso2 + commons-codec + provided + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Authentication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Authentication.java new file mode 100644 index 000000000..42257b794 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Authentication.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; + +/** + * Authentication related REST-API implementation. + */ +@Produces({ "application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class Authentication { + + private static Log log = LogFactory.getLog(Authentication.class); +} + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java new file mode 100644 index 000000000..8acf4efe9 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java @@ -0,0 +1,98 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.MDMAppConstants; +import org.wso2.carbon.mdm.api.util.ResponsePayload; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + +/** + * General Tenant Configuration REST-API implementation. + * All end points support JSON, XMl with content negotiation. + */ +@WebService +@Produces({ "application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class Configuration { + + private static Log log = LogFactory.getLog(Configuration.class); + + @POST + public ResponsePayload saveTenantConfiguration(TenantConfiguration configuration) + throws MDMAPIException { + ResponsePayload responseMsg = new ResponsePayload(); + try { + MDMAPIUtils.getTenantConfigurationManagementService().saveConfiguration(configuration, + MDMAppConstants.RegistryConstants.GENERAL_CONFIG_RESOURCE_PATH); + //Schedule the task service + MDMAPIUtils.scheduleTaskService(MDMAPIUtils.getNotifierFrequency(configuration)); + Response.status(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Tenant configuration saved successfully."); + responseMsg.setStatusCode(HttpStatus.SC_CREATED); + return responseMsg; + } catch (ConfigurationManagementException e) { + String msg = "Error occurred while saving the tenant configuration."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @GET + public TenantConfiguration getConfiguration() throws MDMAPIException { + String msg; + try { + return MDMAPIUtils.getTenantConfigurationManagementService().getConfiguration(MDMAppConstants. + RegistryConstants.GENERAL_CONFIG_RESOURCE_PATH); + } catch (ConfigurationManagementException e) { + msg = "Error occurred while retrieving the tenant configuration."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @PUT + public ResponsePayload updateConfiguration(TenantConfiguration configuration) throws MDMAPIException { + ResponsePayload responseMsg = new ResponsePayload(); + try { + MDMAPIUtils.getTenantConfigurationManagementService().saveConfiguration(configuration, + MDMAppConstants.RegistryConstants.GENERAL_CONFIG_RESOURCE_PATH); + //Schedule the task service + MDMAPIUtils.scheduleTaskService(MDMAPIUtils.getNotifierFrequency(configuration)); + Response.status(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Tenant configuration updated successfully."); + responseMsg.setStatusCode(HttpStatus.SC_CREATED); + return responseMsg; + } catch (ConfigurationManagementException e) { + String msg = "Error occurred while updating the tenant configuration."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceNotification.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceNotification.java new file mode 100644 index 000000000..9a8567572 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceNotification.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException; +import org.wso2.carbon.device.mgt.common.notification.mgt.Notification; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * DeviceNotification management REST-API implementation. + * All end points support JSON, XMl with content negotiation. + */ +@WebService +@Produces({ "application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class DeviceNotification { + + private static Log log = LogFactory.getLog(Configuration.class); + + @GET + public List getNotifications() throws MDMAPIException { + String msg; + try { + return MDMAPIUtils.getNotificationManagementService().getAllNotifications(); + } catch (NotificationManagementException e) { + msg = "Error occurred while retrieving the notification list."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @GET + @Path("{status}") + public List getNotificationsByStatus(@PathParam("status") Notification.Status status) + throws MDMAPIException { + String msg; + try { + return MDMAPIUtils.getNotificationManagementService().getNotificationsByStatus(status); + } catch (NotificationManagementException e) { + msg = "Error occurred while retrieving the notification list."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @PUT + @Path("{id}/{status}") + public ResponsePayload updateNotificationStatus(@PathParam("id") int id, + @PathParam("status") Notification.Status status) + throws MDMAPIException{ + ResponsePayload responseMsg = new ResponsePayload(); + try { + MDMAPIUtils.getNotificationManagementService().updateNotificationStatus(id, status); + Response.status(HttpStatus.SC_ACCEPTED); + responseMsg.setMessageFromServer("Notification status updated successfully."); + responseMsg.setStatusCode(HttpStatus.SC_ACCEPTED); + return responseMsg; + } catch (NotificationManagementException e) { + String msg = "Error occurred while updating notification status."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @POST + public ResponsePayload addNotification(Notification notification) + throws MDMAPIException{ + ResponsePayload responseMsg = new ResponsePayload(); + try { + MDMAPIUtils.getNotificationManagementService().addNotification(notification); + Response.status(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Notification has added successfully."); + responseMsg.setStatusCode(HttpStatus.SC_CREATED); + return responseMsg; + } catch (NotificationManagementException e) { + String msg = "Error occurred while updating notification status."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java new file mode 100644 index 000000000..1cd357b94 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; + +import javax.ws.rs.*; +import java.util.List; + +/** + * Features + */ +@Produces({"application/json", "application/xml"}) +@Consumes({"application/json", "application/xml"}) +public class Feature { + private static Log log = LogFactory.getLog(Feature.class); + + /** + * Get all features for Mobile Device Type + * + * @return Feature + * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * + */ + @GET + @Path("/{type}") + public List getFeatures(@PathParam("type") String type) + throws MDMAPIException { + List features; + DeviceManagementProviderService dmService; + try { + dmService = MDMAPIUtils.getDeviceManagementService(); + features = dmService.getFeatureManager(type).getFeatures(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the list of features"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return features; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/License.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/License.java new file mode 100644 index 000000000..1b1e6c3d0 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/License.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * This class represents license related operations. + */ +public class License { + + private static Log log = LogFactory.getLog(License.class); + + /** + * This method returns the license text related to a given device type and language code. + * + * @param deviceType Device type, ex: android, ios + * @param languageCode Language code, ex: en_US + * @return Returns the license text + * @throws MDMAPIException If the device type or language code arguments are not available or invalid. + */ + @GET + @Path ("{deviceType}/{languageCode}") + @Produces ({MediaType.APPLICATION_JSON}) + public Response getLicense(@PathParam ("deviceType") String deviceType, + @PathParam ("languageCode") String languageCode) throws MDMAPIException { + + org.wso2.carbon.device.mgt.common.license.mgt.License license; + ResponsePayload responsePayload = new ResponsePayload(); + try { + license = MDMAPIUtils.getDeviceManagementService().getLicense(deviceType, languageCode); + if (license == null) { + return Response.status(HttpStatus.SC_NOT_FOUND).build(); + } + responsePayload = ResponsePayload.statusCode(HttpStatus.SC_OK). + messageFromServer("License for '" + deviceType + "' was retrieved successfully"). + responseContent(license.getText()). + build(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the license configured for '" + deviceType + "' device type"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * This method is used to add license to a specific device type. + * + * @param deviceType Device type, ex: android, ios + * @param license License object + * @return Returns the acknowledgement for the action + * @throws MDMAPIException + */ + @POST + @Path ("{deviceType}") + public Response addLicense(@PathParam ("deviceType") String deviceType, + org.wso2.carbon.device.mgt.common.license.mgt.License license) throws MDMAPIException { + + ResponsePayload responsePayload; + try { + MDMAPIUtils.getDeviceManagementService().addLicense(deviceType, license); + responsePayload = ResponsePayload.statusCode(HttpStatus.SC_OK). + messageFromServer("License added successfully for '" + deviceType + "' device type"). + build(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while adding license for '" + deviceType + "' device type"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java new file mode 100644 index 000000000..be7c9bda3 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java @@ -0,0 +1,218 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.*; +import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Device related operations + */ +public class MobileDevice { + private static Log log = LogFactory.getLog(MobileDevice.class); + + /** + * Get all devices. We have to use accept all the necessary query parameters sent by datatable. + * Hence had to put lot of query params here. + * + * @return Device List + * @throws MDMAPIException + */ + @GET + public Object getAllDevices(@QueryParam("type") String type, @QueryParam("user") String user, + @QueryParam("role") String role, @QueryParam("status") EnrolmentInfo.Status status, + @QueryParam("start") int startIdx, @QueryParam("length") int length, + @QueryParam("device-name") String deviceName, + @QueryParam("ownership") EnrolmentInfo.OwnerShip ownership + ) throws MDMAPIException { + try { + DeviceManagementProviderService service = MDMAPIUtils.getDeviceManagementService(); + //Length > 0 means this is a pagination request. + if (length > 0) { + PaginationRequest paginationRequest = new PaginationRequest(startIdx, length); + paginationRequest.setDeviceName(deviceName); + paginationRequest.setOwner(user); + if (ownership != null) { + paginationRequest.setOwnership(ownership.toString()); + } + if (status != null) { + paginationRequest.setStatus(status.toString()); + } + paginationRequest.setDeviceType(type); + return service.getAllDevices(paginationRequest); + } + + List allDevices = null; + if ((type != null) && !type.isEmpty()) { + allDevices = service.getAllDevices(type); + } else if ((user != null) && !user.isEmpty()) { + allDevices = service.getDevicesOfUser(user); + } else if ((role != null) && !role.isEmpty()) { + allDevices = service.getAllDevicesOfRole(role); + } else if (status != null) { + allDevices = service.getDevicesByStatus(status); + } else if (deviceName != null) { + allDevices = service.getDevicesByName(deviceName); + } else { + allDevices = service.getAllDevices(); + } + return allDevices; + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching the device list."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + /** + * Fetch device details for a given device type and device Id. + * + * @return Device wrapped inside Response + * @throws MDMAPIException + */ + @GET + @Path("view") + @Produces({MediaType.APPLICATION_JSON}) + public Response getDevice(@QueryParam("type") String type, + @QueryParam("id") String id) throws MDMAPIException { + DeviceIdentifier deviceIdentifier = MDMAPIUtils.instantiateDeviceIdentifier(type, id); + DeviceManagementProviderService deviceManagementProviderService = MDMAPIUtils.getDeviceManagementService(); + Device device; + try { + device = deviceManagementProviderService.getDevice(deviceIdentifier); + } catch (DeviceManagementException e) { + String error = "Error occurred while fetching the device information."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + if (device == null) { + responsePayload.setStatusCode(HttpStatus.SC_NOT_FOUND); + responsePayload.setMessageFromServer("Requested device by type: " + + type + " and id: " + id + " does not exist."); + return Response.status(HttpStatus.SC_NOT_FOUND).entity(responsePayload).build(); + } else { + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Sending Requested device by type: " + type + " and id: " + id + "."); + responsePayload.setResponseContent(device); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + } + + /** + * Fetch Android device details of a given user. + * + * @param user User Name + * @param tenantDomain tenant domain + * @return Device + * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + */ + @GET + @Path("user/{user}/{tenantDomain}") + public List getDeviceByUser(@PathParam("user") String user, + @PathParam("tenantDomain") String tenantDomain) throws MDMAPIException { + List devices; + try { + devices = MDMAPIUtils.getDeviceManagementService().getDevicesOfUser(user); + if (devices == null) { + Response.status(Response.Status.NOT_FOUND); + } + return devices; + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching the devices list of given user."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + /** + * Get current device count + * + * @return device count + * @throws MDMAPIException + */ + @GET + @Path("count") + public int getDeviceCount() throws MDMAPIException { + try { + return MDMAPIUtils.getDeviceManagementService().getDeviceCount(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching the device count."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + /** + * Get the list of devices that matches with the given name. + * + * @param deviceName Device name + * @param tenantDomain Callee tenant domain + * @return list of devices. + * @throws MDMAPIException If some unusual behaviour is observed while fetching the device list + */ + @GET + @Path("name/{name}/{tenantDomain}") + public List getDevicesByName(@PathParam("name") String deviceName, + @PathParam("tenantDomain") String tenantDomain) throws MDMAPIException { + + List devices; + try { + devices = MDMAPIUtils.getDeviceManagementService().getDevicesByName(deviceName); + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching the devices list of device name."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return devices; + } + + /** + * Get the list of available device types. + * + * @return list of device types. + * @throws MDMAPIException If some unusual behaviour is observed while fetching the device list + */ + @GET + @Path("types") + public List getDeviceTypes() throws MDMAPIException { + + List deviceTypes; + try { + deviceTypes = MDMAPIUtils.getDeviceManagementService().getAvailableDeviceTypes(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching the list of device types."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return deviceTypes; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java new file mode 100644 index 000000000..a775318dd --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java @@ -0,0 +1,225 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.PaginationRequest; +import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.device.mgt.common.Platform; +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.OperationManagementException; +import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.context.DeviceOperationContext; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.MDMAndroidOperationUtil; +import org.wso2.carbon.mdm.api.util.MDMIOSOperationUtil; +import org.wso2.carbon.mdm.api.util.ResponsePayload; +import org.wso2.carbon.mdm.beans.ApplicationWrapper; +import org.wso2.carbon.mdm.beans.MobileApp; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; + +/** + * Operation related REST-API implementation. + */ +@Produces({"application/json", "application/xml"}) +@Consumes({"application/json", "application/xml"}) +public class Operation { + + private static Log log = LogFactory.getLog(Operation.class); + + @GET + public List getAllOperations() + throws MDMAPIException { + List operations; + DeviceManagementProviderService dmService; + try { + dmService = MDMAPIUtils.getDeviceManagementService(); + operations = dmService.getOperations(null); + } catch (OperationManagementException e) { + String msg = "Error occurred while fetching the operations for the device."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return operations; + } + + @GET + @Path("paginate/{type}/{id}") + public PaginationResult getDeviceOperations( + @PathParam("type") String type, @PathParam("id") String id, @QueryParam("start") int startIdx, + @QueryParam("length") int length, @QueryParam("search") String search) + throws MDMAPIException { + PaginationResult operations; + DeviceManagementProviderService dmService; + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + PaginationRequest paginationRequest = new PaginationRequest(startIdx, length); + try { + deviceIdentifier.setType(type); + deviceIdentifier.setId(id); + dmService = MDMAPIUtils.getDeviceManagementService(); + operations = dmService.getOperations(deviceIdentifier, paginationRequest); + } catch (OperationManagementException e) { + String msg = "Error occurred while fetching the operations for the device."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return operations; + } + + @GET + @Path("{type}/{id}") + public List getDeviceOperations( + @PathParam("type") String type, @PathParam("id") String id) + throws MDMAPIException { + List operations; + DeviceManagementProviderService dmService; + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + try { + deviceIdentifier.setType(type); + deviceIdentifier.setId(id); + dmService = MDMAPIUtils.getDeviceManagementService(); + operations = dmService.getOperations(deviceIdentifier); + } catch (OperationManagementException e) { + String msg = "Error occurred while fetching the operations for the device."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return operations; + } + + @POST + public ResponsePayload addOperation(DeviceOperationContext operationContext) throws MDMAPIException { + DeviceManagementProviderService dmService; + ResponsePayload responseMsg = new ResponsePayload(); + try { + dmService = MDMAPIUtils.getDeviceManagementService(); + int operationId = dmService.addOperation(operationContext.getOperation(), + operationContext.getDevices()); + if (operationId>0) { + Response.status(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Operation has added successfully."); + } + return responseMsg; + } catch (OperationManagementException e) { + String msg = "Error occurred while saving the operation"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @GET + @Path("{type}/{id}/apps") + public List getInstalledApps( + @PathParam("type") String type, + @PathParam("id") String id) + throws MDMAPIException { + List applications; + ApplicationManagementProviderService appManagerConnector; + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + try { + deviceIdentifier.setType(type); + deviceIdentifier.setId(id); + appManagerConnector = MDMAPIUtils.getAppManagementService(); + applications = appManagerConnector.getApplicationListForDevice(deviceIdentifier); + } catch (ApplicationManagementException e) { + String msg = "Error occurred while fetching the apps of the device."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return applications; + } + + @POST + @Path("installApp/{tenantDomain}") + public ResponsePayload installApplication(ApplicationWrapper applicationWrapper, + @PathParam("tenantDomain") String tenantDomain) throws MDMAPIException { + ResponsePayload responseMsg = new ResponsePayload(); + ApplicationManager appManagerConnector; + org.wso2.carbon.device.mgt.common.operation.mgt.Operation operation = null; + ArrayList deviceIdentifiers; + try { + appManagerConnector = MDMAPIUtils.getAppManagementService(); + MobileApp mobileApp = applicationWrapper.getApplication(); + + if (applicationWrapper.getDeviceIdentifiers() != null) { + for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) { + deviceIdentifiers = new ArrayList(); + + if (deviceIdentifier.getType().equals(Platform.android.toString())) { + operation = MDMAndroidOperationUtil.createInstallAppOperation(mobileApp); + } else if (deviceIdentifier.getType().equals(Platform.ios.toString())) { + operation = MDMIOSOperationUtil.createInstallAppOperation(mobileApp); + } + deviceIdentifiers.add(deviceIdentifier); + } + appManagerConnector.installApplicationForDevices(operation, applicationWrapper.getDeviceIdentifiers()); + } + return responseMsg; + } catch (ApplicationManagementException e) { + String msg = "Error occurred while saving the operation"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @POST + @Path("uninstallApp/{tenantDomain}") + public ResponsePayload uninstallApplication(ApplicationWrapper applicationWrapper, + @PathParam("tenantDomain") String tenantDomain) throws MDMAPIException { + ResponsePayload responseMsg = new ResponsePayload(); + ApplicationManager appManagerConnector; + org.wso2.carbon.device.mgt.common.operation.mgt.Operation operation = null; + ArrayList deviceIdentifiers; + try { + appManagerConnector = MDMAPIUtils.getAppManagementService(); + MobileApp mobileApp = applicationWrapper.getApplication(); + + if (applicationWrapper.getDeviceIdentifiers() != null) { + for (DeviceIdentifier deviceIdentifier : applicationWrapper.getDeviceIdentifiers()) { + deviceIdentifiers = new ArrayList(); + + if (deviceIdentifier.getType().equals(Platform.android.toString())) { + operation = MDMAndroidOperationUtil.createAppUninstallOperation(mobileApp); + } else if (deviceIdentifier.getType().equals(Platform.ios.toString())) { + operation = MDMIOSOperationUtil.createAppUninstallOperation(mobileApp); + } + deviceIdentifiers.add(deviceIdentifier); + } + appManagerConnector.installApplicationForDevices(operation, applicationWrapper.getDeviceIdentifiers()); + } + return responseMsg; + } catch (ApplicationManagementException e) { + String msg = "Error occurred while saving the operation"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java new file mode 100644 index 000000000..dea04d31b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java @@ -0,0 +1,475 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; +import org.wso2.carbon.mdm.beans.PolicyWrapper; +import org.wso2.carbon.mdm.beans.PriorityUpdatedPolicyWrapper; +import org.wso2.carbon.mdm.util.MDMUtil; +import org.wso2.carbon.policy.mgt.common.PolicyAdministratorPoint; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.common.PolicyMonitoringTaskException; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceData; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; +import org.wso2.carbon.policy.mgt.core.task.TaskScheduleService; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; + +public class Policy { + private static Log log = LogFactory.getLog(Policy.class); + + @POST + @Path("inactive-policy") + public ResponsePayload addPolicy(PolicyWrapper policyWrapper) throws MDMAPIException { + + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + ResponsePayload responseMsg = new ResponsePayload(); + org.wso2.carbon.policy.mgt.common.Policy policy = new org.wso2.carbon.policy.mgt.common.Policy(); + policy.setPolicyName(policyWrapper.getPolicyName()); + policy.setProfileId(policyWrapper.getProfileId()); + policy.setDescription(policyWrapper.getDescription()); + policy.setProfile(MDMUtil.convertProfile(policyWrapper.getProfile())); + policy.setOwnershipType(policyWrapper.getOwnershipType()); + policy.setRoles(policyWrapper.getRoles()); + policy.setUsers(policyWrapper.getUsers()); + policy.setTenantId(policyWrapper.getTenantId()); + policy.setCompliance(policyWrapper.getCompliance()); + + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + pap.addPolicy(policy); + Response.status(HttpStatus.SC_CREATED); + responseMsg.setStatusCode(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Policy has been added successfully."); + return responseMsg; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + + @POST + @Path("active-policy") + public ResponsePayload addActivePolicy(PolicyWrapper policyWrapper) throws MDMAPIException { + + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + ResponsePayload responseMsg = new ResponsePayload(); + org.wso2.carbon.policy.mgt.common.Policy policy = new org.wso2.carbon.policy.mgt.common.Policy(); + policy.setPolicyName(policyWrapper.getPolicyName()); + policy.setProfileId(policyWrapper.getProfileId()); + policy.setDescription(policyWrapper.getDescription()); + policy.setProfile(MDMUtil.convertProfile(policyWrapper.getProfile())); + policy.setOwnershipType(policyWrapper.getOwnershipType()); + policy.setRoles(policyWrapper.getRoles()); + policy.setUsers(policyWrapper.getUsers()); + policy.setTenantId(policyWrapper.getTenantId()); + policy.setCompliance(policyWrapper.getCompliance()); + policy.setActive(true); + + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + pap.addPolicy(policy); + Response.status(HttpStatus.SC_CREATED); + responseMsg.setStatusCode(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Policy has been added successfully."); + return responseMsg; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + + @GET + @Produces({MediaType.APPLICATION_JSON}) + public Response getAllPolicies() throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + List policies; + try { + PolicyAdministratorPoint policyAdministratorPoint = policyManagementService.getPAP(); + policies = policyAdministratorPoint.getPolicies(); + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Sending all retrieved device policies."); + responsePayload.setResponseContent(policies); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + @GET + @Produces({MediaType.APPLICATION_JSON}) + @Path("{id}") + public Response getPolicy(@PathParam("id") int policyId) throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + final org.wso2.carbon.policy.mgt.common.Policy policy; + try { + PolicyAdministratorPoint policyAdministratorPoint = policyManagementService.getPAP(); + policy = policyAdministratorPoint.getPolicy(policyId); + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + if (policy == null){ + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_NOT_FOUND); + responsePayload.setMessageFromServer("Policy for ID " + policyId + " not found."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Sending all retrieved device policies."); + responsePayload.setResponseContent(policy); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + @GET + @Path("count") + public int getPolicyCount() throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + try { + PolicyAdministratorPoint policyAdministratorPoint = policyManagementService.getPAP(); + return policyAdministratorPoint.getPolicyCount(); + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + + @PUT + @Path("{id}") + public ResponsePayload updatePolicy(PolicyWrapper policyWrapper, @PathParam("id") int policyId) + throws MDMAPIException { +// PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); +// ResponsePayload responseMsg = new ResponsePayload(); +// try { +// PolicyAdministratorPoint pap = policyManagementService.getPAP(); +// org.wso2.carbon.policy.mgt.common.Policy previousPolicy = pap.getPolicy(policyId); +// policy.setProfile(pap.getProfile(previousPolicy.getProfileId())); +// policy.setId(previousPolicy.getId()); +// pap.updatePolicy(policy); +// Response.status(HttpStatus.SC_OK); +// responseMsg.setMessageFromServer("Policy has been updated successfully."); +// return responseMsg; +// } catch (PolicyManagementException e) { +// String error = "Policy Management related exception"; +// log.error(error, e); +// throw new MDMAPIException(error, e); +// } + + + + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + ResponsePayload responseMsg = new ResponsePayload(); + org.wso2.carbon.policy.mgt.common.Policy policy = new org.wso2.carbon.policy.mgt.common.Policy(); + policy.setPolicyName(policyWrapper.getPolicyName()); + policy.setId(policyId); + policy.setProfileId(policyWrapper.getProfileId()); + policy.setDescription(policyWrapper.getDescription()); + policy.setProfile(MDMUtil.convertProfile(policyWrapper.getProfile())); + policy.setOwnershipType(policyWrapper.getOwnershipType()); + policy.setRoles(policyWrapper.getRoles()); + policy.setUsers(policyWrapper.getUsers()); + policy.setTenantId(policyWrapper.getTenantId()); + policy.setCompliance(policyWrapper.getCompliance()); + // policy.setActive(true); + + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); +// pap.addPolicy(policy); + pap.updatePolicy(policy); +// Response.status(HttpStatus.SC_CREATED); + Response.status(HttpStatus.SC_OK); + responseMsg.setStatusCode(HttpStatus.SC_CREATED); +// responseMsg.setMessageFromServer("Policy has been added successfully."); + responseMsg.setMessageFromServer("Policy has been updated successfully."); + return responseMsg; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception in policy update."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + + @PUT + @Path("priorities") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response updatePolicyPriorities(List priorityUpdatedPolicies) + throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + List policiesToUpdate = + new ArrayList(priorityUpdatedPolicies.size()); + int i; + for (i = 0; i < priorityUpdatedPolicies.size(); i++) { + org.wso2.carbon.policy.mgt.common.Policy policyObj = new org.wso2.carbon.policy.mgt.common.Policy(); + policyObj.setId(priorityUpdatedPolicies.get(i).getId()); + policyObj.setPriorityId(priorityUpdatedPolicies.get(i).getPriority()); + policiesToUpdate.add(policyObj); + } + boolean policiesUpdated; + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + policiesUpdated = pap.updatePolicyPriorities(policiesToUpdate); + } catch (PolicyManagementException e) { + String error = "Exception in updating policy priorities."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + if (policiesUpdated) { + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Policy Priorities successfully updated."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } else { + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer("Policy priorities did not update. Bad Request."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } + } + + @POST + @Path("bulk-remove") + @Consumes("application/json") + @Produces("application/json") + public Response bulkRemovePolicy(List policyIds) throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + boolean policyDeleted = true; + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + for(int i : policyIds) { + org.wso2.carbon.policy.mgt.common.Policy policy = pap.getPolicy(i); + if(!pap.deletePolicy(policy)){ + policyDeleted = false; + } + } + } catch (PolicyManagementException e) { + String error = "Exception in deleting policies."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + if (policyDeleted) { + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Policies have been successfully deleted."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } else { + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer("Policy does not exist."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } + } + +// @GET +// @Path("task/{mf}") +// public int taskService(@PathParam("mf") int monitoringFrequency) throws MDMAPIException { +// int policyCount = 0; +// PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); +// try { +// TaskScheduleService taskScheduleService = policyManagementService.getTaskScheduleService(); +// taskScheduleService.startTask(monitoringFrequency); +// return policyCount; +// } catch (PolicyMonitoringTaskException e) { +// String error = "Policy Management related exception"; +// log.error(error, e); +// throw new MDMAPIException(error, e); +// } +// } + + + @PUT + @Produces("application/json") + @Path("activate") + public Response activatePolicy(List policyIds) throws MDMAPIException { + try { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + for(int i : policyIds) { + pap.activatePolicy(i); + } + } catch (PolicyManagementException e) { + String error = "Exception in activating policies."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Selected policies have been successfully activated."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + + } + + + @PUT + @Produces("application/json") + @Path("inactivate") + public Response inactivatePolicy(List policyIds) throws MDMAPIException { + + try { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + for(int i : policyIds) { + pap.inactivatePolicy(i); + } + } catch (PolicyManagementException e) { + String error = "Exception in inactivating policies."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Selected policies have been successfully inactivated."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + + @PUT + @Produces("application/json") + @Path("apply-changes") + public Response applyChanges() throws MDMAPIException { + + try { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + pap.publishChanges(); + + + } catch (PolicyManagementException e) { + String error = "Exception in applying changes."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Changes have been successfully updated."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + @GET + @Path("start-task/{milliseconds}") + public Response startTaskService(@PathParam("milliseconds") int monitoringFrequency) throws MDMAPIException { + + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + try { + TaskScheduleService taskScheduleService = policyManagementService.getTaskScheduleService(); + taskScheduleService.startTask(monitoringFrequency); + + + } catch (PolicyMonitoringTaskException e) { + String error = "Policy Management related exception."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Policy monitoring service started successfully."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + + @GET + @Path("update-task/{milliseconds}") + public Response updateTaskService(@PathParam("milliseconds") int monitoringFrequency) throws MDMAPIException { + + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + try { + TaskScheduleService taskScheduleService = policyManagementService.getTaskScheduleService(); + taskScheduleService.updateTask(monitoringFrequency); + + } catch (PolicyMonitoringTaskException e) { + String error = "Policy Management related exception."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Policy monitoring service updated successfully."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + + @GET + @Path("stop-task") + public Response stopTaskService() throws MDMAPIException { + + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + try { + TaskScheduleService taskScheduleService = policyManagementService.getTaskScheduleService(); + taskScheduleService.stopTask(); + + } catch (PolicyMonitoringTaskException e) { + String error = "Policy Management related exception."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Policy monitoring service stopped successfully."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + + @GET + @Path("{type}/{id}") + public ComplianceData getComplianceDataOfDevice(@PathParam("type") String type, @PathParam("id") String id) throws + MDMAPIException { + try { + DeviceIdentifier deviceIdentifier = MDMAPIUtils.instantiateDeviceIdentifier(type, id); + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + return policyManagementService.getDeviceCompliance(deviceIdentifier); + } catch (PolicyComplianceException e) { + String error = "Error occurred while getting the compliance data."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + + @GET + @Path("{type}/{id}/active-policy") + public org.wso2.carbon.policy.mgt.common.Policy getDeviceActivePolicy(@PathParam("type") String type, + @PathParam("id") String id) throws MDMAPIException { + try { + DeviceIdentifier deviceIdentifier = MDMAPIUtils.instantiateDeviceIdentifier(type, id); + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + return policyManagementService.getAppliedPolicyToDevice(deviceIdentifier); + } catch (PolicyManagementException e) { + String error = "Error occurred while getting the current policy."; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Profile.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Profile.java new file mode 100644 index 000000000..4cf216ec6 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Profile.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; +import org.wso2.carbon.policy.mgt.common.PolicyAdministratorPoint; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; + +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +public class Profile { + private static Log log = LogFactory.getLog(Profile.class); + + @POST + public org.wso2.carbon.policy.mgt.common.Profile addProfile(org.wso2.carbon.policy.mgt.common.Profile profile) throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + profile = pap.addProfile(profile); + Response.status(HttpStatus.SC_CREATED); + return profile; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + @POST + @Path("{id}") + public ResponsePayload updateProfile(org.wso2.carbon.policy.mgt.common.Profile profile, @PathParam("id") String profileId) + throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + ResponsePayload responseMsg = new ResponsePayload(); + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + pap.updateProfile(profile); + Response.status(HttpStatus.SC_OK); + responseMsg.setMessageFromServer("Profile has been updated successfully."); + return responseMsg; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } + @DELETE + @Path("{id}") + public ResponsePayload deleteProfile(@PathParam("id") int profileId) throws MDMAPIException { + PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); + ResponsePayload responseMsg = new ResponsePayload(); + try { + PolicyAdministratorPoint pap = policyManagementService.getPAP(); + org.wso2.carbon.policy.mgt.common.Profile profile = pap.getProfile(profileId); + pap.deleteProfile(profile); + Response.status(HttpStatus.SC_OK); + responseMsg.setMessageFromServer("Profile has been deleted successfully."); + return responseMsg; + } catch (PolicyManagementException e) { + String error = "Policy Management related exception"; + log.error(error, e); + throw new MDMAPIException(error, e); + } + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java new file mode 100644 index 000000000..a0adeed6a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java @@ -0,0 +1,422 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.CarbonConstants; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; +import org.wso2.carbon.mdm.beans.RoleWrapper; +import org.wso2.carbon.mdm.util.SetReferenceTransformer; +import org.wso2.carbon.user.api.*; +import org.wso2.carbon.user.core.common.AbstractUserStoreManager; +import org.wso2.carbon.user.mgt.UserRealmProxy; +import org.wso2.carbon.user.mgt.common.UIPermissionNode; +import org.wso2.carbon.user.mgt.common.UserAdminException; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Role { + + private static Log log = LogFactory.getLog(Role.class); + + /** + * Get user roles (except all internal roles) from system. + * + * @return A list of users + * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + */ + @GET + @Produces ({MediaType.APPLICATION_JSON}) + public Response getRoles() throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + String[] roles; + try { + if (log.isDebugEnabled()) { + log.debug("Getting the list of user roles"); + } + roles = userStoreManager.getRoleNames(); + + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of user roles."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + // removing all internal roles and roles created for Service-providers + List filteredRoles = new ArrayList(); + for (String role : roles) { + if (!(role.startsWith("Internal/") || role.startsWith("Application/"))) { + filteredRoles.add(role); + } + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("All user roles were successfully retrieved."); + responsePayload.setResponseContent(filteredRoles); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get user roles by user store(except all internal roles) from system. + * + * @return A list of users + * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + */ + @GET + @Path ("{userStore}") + @Produces ({MediaType.APPLICATION_JSON}) + public Response getRoles(@PathParam ("userStore") String userStore) throws MDMAPIException { + AbstractUserStoreManager abstractUserStoreManager = (AbstractUserStoreManager) MDMAPIUtils.getUserStoreManager(); + String[] roles; + try { + if (log.isDebugEnabled()) { + log.debug("Getting the list of user roles"); + } + roles = abstractUserStoreManager.getRoleNames(userStore+"/*", -1, false, true, true); + + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of user roles."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + // removing all internal roles and roles created for Service-providers + List filteredRoles = new ArrayList(); + for (String role : roles) { + if (!(role.startsWith("Internal/") || role.startsWith("Application/"))) { + filteredRoles.add(role); + } + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("All user roles were successfully retrieved."); + responsePayload.setResponseContent(filteredRoles); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get user roles by providing a filtering criteria(except all internal roles & system roles) from system. + * + * @return A list of users + * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + */ + @GET + @Path ("search") + @Produces ({MediaType.APPLICATION_JSON}) + public Response getMatchingRoles(@QueryParam ("filter") String filter) throws MDMAPIException { + AbstractUserStoreManager abstractUserStoreManager = (AbstractUserStoreManager) MDMAPIUtils.getUserStoreManager(); + String[] roles; + try { + if (log.isDebugEnabled()) { + log.debug("Getting the list of user roles using filter : " + filter); + } + roles = abstractUserStoreManager.getRoleNames("*" + filter + "*", -1, true, true, true); + + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of user roles using the filter : " + filter; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + // removing all internal roles and roles created for Service-providers + List filteredRoles = new ArrayList(); + for (String role : roles) { + if (!(role.startsWith("Internal/") || role.startsWith("Application/"))) { + filteredRoles.add(role); + } + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("All matching user roles were successfully retrieved."); + responsePayload.setResponseContent(filteredRoles); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get role permissions. + * + * @return list of permissions + * @throws MDMAPIException + */ + @GET + @Path ("permissions") + @Produces ({MediaType.APPLICATION_JSON}) + public ResponsePayload getPermissions(@QueryParam ("rolename") String roleName) throws MDMAPIException { + final UserRealm userRealm = MDMAPIUtils.getUserRealm(); + org.wso2.carbon.user.core.UserRealm userRealmCore = null; + final UIPermissionNode rolePermissions; + if (userRealm instanceof org.wso2.carbon.user.core.UserRealm) { + userRealmCore = (org.wso2.carbon.user.core.UserRealm) userRealm; + } + + try { + final UserRealmProxy userRealmProxy = new UserRealmProxy(userRealmCore); + rolePermissions = userRealmProxy.getRolePermissions(roleName, MultitenantConstants.SUPER_TENANT_ID); + UIPermissionNode[] deviceMgtPermissions = new UIPermissionNode[2]; + + for (UIPermissionNode permissionNode : rolePermissions.getNodeList()) { + if (permissionNode.getResourcePath().equals("/permission/admin")) { + for (UIPermissionNode node : permissionNode.getNodeList()) { + if (node.getResourcePath().equals("/permission/admin/device-mgt")) { + deviceMgtPermissions[0] = node; + } else if (node.getResourcePath().equals("/permission/admin/login")) { + deviceMgtPermissions[1] = node; + } + } + } + } + rolePermissions.setNodeList(deviceMgtPermissions); + } catch (UserAdminException e) { + String msg = "Error occurred while retrieving the user role"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("All permissions retrieved"); + responsePayload.setResponseContent(rolePermissions); + return responsePayload; + } + + /** + * Get user role of the system + * + * @return user role + * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + */ + @GET + @Path("role") + @Produces ({MediaType.APPLICATION_JSON}) + public ResponsePayload getRole(@QueryParam ("rolename") String roleName) throws MDMAPIException { + final UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + final UserRealm userRealm = MDMAPIUtils.getUserRealm(); + org.wso2.carbon.user.core.UserRealm userRealmCore = null; + if (userRealm instanceof org.wso2.carbon.user.core.UserRealm) { + userRealmCore = (org.wso2.carbon.user.core.UserRealm) userRealm; + } + + RoleWrapper roleWrapper = new RoleWrapper(); + try { + final UserRealmProxy userRealmProxy = new UserRealmProxy(userRealmCore); + if (log.isDebugEnabled()) { + log.debug("Getting the list of user roles"); + } + if (userStoreManager.isExistingRole(roleName)) { + roleWrapper.setRoleName(roleName); + roleWrapper.setUsers(userStoreManager.getUserListOfRole(roleName)); + // Get the permission nodes and hand picking only device management and login perms + final UIPermissionNode rolePermissions = + userRealmProxy.getRolePermissions(roleName, MultitenantConstants.SUPER_TENANT_ID); + UIPermissionNode[] deviceMgtPermissions = new UIPermissionNode[2]; + + for (UIPermissionNode permissionNode : rolePermissions.getNodeList()) { + if (permissionNode.getResourcePath().equals("/permission/admin")) { + for (UIPermissionNode node : permissionNode.getNodeList()) { + if (node.getResourcePath().equals("/permission/admin/device-mgt")) { + deviceMgtPermissions[0] = node; + } else if (node.getResourcePath().equals("/permission/admin/login")) { + deviceMgtPermissions[1] = node; + } + } + } + } + rolePermissions.setNodeList(deviceMgtPermissions); + ArrayList permList = new ArrayList(); + iteratePermissions(rolePermissions, permList); + roleWrapper.setPermissionList(rolePermissions); + String[] permListAr = new String[permList.size()]; + roleWrapper.setPermissions(permList.toArray(permListAr)); + } + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the user role"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } catch (UserAdminException e) { + String msg = "Error occurred while retrieving the user role"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("All user roles were successfully retrieved."); + responsePayload.setResponseContent(roleWrapper); + return responsePayload; + } + + /** + * API is used to persist a new Role + * + * @param roleWrapper + * @return + * @throws MDMAPIException + */ + @POST + @Produces ({MediaType.APPLICATION_JSON}) + public Response addRole(RoleWrapper roleWrapper) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + try { + if (log.isDebugEnabled()) { + log.debug("Persisting the role to user store"); + } + Permission[] permissions = null; + if (roleWrapper.getPermissions() != null && roleWrapper.getPermissions().length > 0) { + permissions = new Permission[roleWrapper.getPermissions().length]; + + for (int i = 0; i < permissions.length; i++) { + String permission = roleWrapper.getPermissions()[i]; + permissions[i] = new Permission(permission, CarbonConstants.UI_PERMISSION_ACTION); + } + } + userStoreManager.addRole(roleWrapper.getRoleName(), roleWrapper.getUsers(), permissions); + } catch (UserStoreException e) { + String msg = e.getMessage(); + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_CREATED).build(); + } + + /** + * API is used to update a role Role + * + * @param roleWrapper + * @return + * @throws MDMAPIException + */ + @PUT + @Produces ({MediaType.APPLICATION_JSON}) + public Response updateRole(@QueryParam ("rolename") String roleName, RoleWrapper roleWrapper) throws + MDMAPIException { + final UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + final AuthorizationManager authorizationManager = MDMAPIUtils.getAuthorizationManager(); + String newRoleName = roleWrapper.getRoleName(); + try { + if (log.isDebugEnabled()) { + log.debug("Updating the role to user store"); + } + if (newRoleName != null && !roleName.equals(newRoleName)) { + userStoreManager.updateRoleName(roleName, newRoleName); + } + if (roleWrapper.getUsers() != null) { + SetReferenceTransformer transformer = new SetReferenceTransformer(); + transformer.transform(Arrays.asList(userStoreManager.getUserListOfRole(newRoleName)), + Arrays.asList(roleWrapper.getUsers())); + final String[] usersToAdd = (String[]) + transformer.getObjectsToAdd().toArray(new String[transformer.getObjectsToAdd().size()]); + final String[] usersToDelete = (String[]) + transformer.getObjectsToRemove().toArray(new String[transformer.getObjectsToRemove().size()]); + userStoreManager.updateUserListOfRole(newRoleName, usersToDelete, usersToAdd); + } + if (roleWrapper.getPermissions() != null) { + // Delete all authorizations for the current role before authorizing the permission tree + authorizationManager.clearRoleAuthorization(roleName); + if (roleWrapper.getPermissions().length > 0) { + for (int i = 0; i < roleWrapper.getPermissions().length; i++) { + String permission = roleWrapper.getPermissions()[i]; + authorizationManager.authorizeRole(roleName, permission, CarbonConstants.UI_PERMISSION_ACTION); + } + } + } + } catch (UserStoreException e) { + String msg = e.getMessage(); + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).build(); + } + + /** + * API is used to delete a role and authorizations + * + * @param roleName + * @return + * @throws MDMAPIException + */ + @DELETE + @Produces ({MediaType.APPLICATION_JSON}) + public Response deleteRole(@QueryParam ("rolename") String roleName) throws MDMAPIException { + final UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + final AuthorizationManager authorizationManager = MDMAPIUtils.getAuthorizationManager(); + try { + if (log.isDebugEnabled()) { + log.debug("Deleting the role in user store"); + } + userStoreManager.deleteRole(roleName); + // Delete all authorizations for the current role before deleting + authorizationManager.clearRoleAuthorization(roleName); + } catch (UserStoreException e) { + String msg = "Error occurred while deleting the role: " + roleName; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).build(); + } + + /** + * API is used to update users of a role + * + * @param roleName + * @param userList + * @return + * @throws MDMAPIException + */ + @PUT + @Path ("users") + @Produces ({MediaType.APPLICATION_JSON}) + public Response updateUsers(@QueryParam ("rolename") String roleName, List userList) + throws MDMAPIException { + final UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + try { + if (log.isDebugEnabled()) { + log.debug("Updating the users of a role"); + } + SetReferenceTransformer transformer = new SetReferenceTransformer(); + transformer.transform(Arrays.asList(userStoreManager.getUserListOfRole(roleName)), + userList); + final String[] usersToAdd = (String[]) + transformer.getObjectsToAdd().toArray(new String[transformer.getObjectsToAdd().size()]); + final String[] usersToDelete = (String[]) + transformer.getObjectsToRemove().toArray(new String[transformer.getObjectsToRemove().size()]); + + userStoreManager.updateUserListOfRole(roleName, usersToDelete, usersToAdd); + } catch (UserStoreException e) { + String msg = "Error occurred while saving the users of the role: " + roleName; + log.error(msg, e); + throw new MDMAPIException(e.getMessage(), e); + } + return Response.status(HttpStatus.SC_OK).build(); + } + + public ArrayList iteratePermissions(UIPermissionNode uiPermissionNode, ArrayList list) { + for (UIPermissionNode permissionNode : uiPermissionNode.getNodeList()) { + list.add(permissionNode.getResourcePath()); + if (permissionNode.getNodeList() != null && permissionNode.getNodeList().length > 0) { + iteratePermissions(permissionNode, list); + } + } + return list; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java new file mode 100644 index 000000000..16c9ee7ca --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java @@ -0,0 +1,786 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.EmailMessageProperties; +import org.wso2.carbon.device.mgt.common.PaginationRequest; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; +import org.wso2.carbon.mdm.beans.UserCredentialWrapper; +import org.wso2.carbon.mdm.beans.UserWrapper; +import org.wso2.carbon.mdm.util.Constants; +import org.wso2.carbon.mdm.util.SetReferenceTransformer; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.api.UserStoreManager; + +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.MediaType; +import javax.ws.rs.core.Response; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TreeSet; + +/** + * This class represents the JAX-RS services of User related functionality. + */ +public class User { + + private static Log log = LogFactory.getLog(User.class); + private String ROLE_EVERYONE = "Internal/everyone"; + + /** + * Method to add user to emm-user-store. + * + * @param userWrapper Wrapper object representing input json payload + * @return {Response} Status of the request wrapped inside Response object + * @throws MDMAPIException + */ + @POST + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response addUser(UserWrapper userWrapper) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + if (userStoreManager.isExistingUser(userWrapper.getUsername())) { + // if user already exists + if (log.isDebugEnabled()) { + log.debug("User by username: " + userWrapper.getUsername() + + " already exists. Therefore, request made to add user was refused."); + } + // returning response with bad request state + responsePayload.setStatusCode(HttpStatus.SC_CONFLICT); + responsePayload. + setMessageFromServer("User by username: " + userWrapper.getUsername() + + " already exists. Therefore, request made to add user was refused."); + return Response.status(HttpStatus.SC_CONFLICT).entity(responsePayload).build(); + } else { + String initialUserPassword = generateInitialUserPassword(); + Map defaultUserClaims = + buildDefaultUserClaims(userWrapper.getFirstname(), userWrapper.getLastname(), + userWrapper.getEmailAddress()); + // calling addUser method of carbon user api + userStoreManager.addUser(userWrapper.getUsername(), initialUserPassword, + userWrapper.getRoles(), defaultUserClaims, null); + // invite newly added user to enroll device + inviteNewlyAddedUserToEnrollDevice(userWrapper.getUsername(), initialUserPassword); + // Outputting debug message upon successful addition of user + if (log.isDebugEnabled()) { + log.debug("User by username: " + userWrapper.getUsername() + " was successfully added."); + } + // returning response with success state + responsePayload.setStatusCode(HttpStatus.SC_CREATED); + responsePayload.setMessageFromServer("User by username: " + userWrapper.getUsername() + + " was successfully added."); + return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); + } + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to add user by username: " + userWrapper.getUsername(); + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } catch (DeviceManagementException e) { + String errorMsg = "Exception in trying to add user by username: " + userWrapper.getUsername(); + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + + /** + * Method to get user information from emm-user-store. + * + * @param username User-name of the user + * @return {Response} Status of the request wrapped inside Response object + * @throws MDMAPIException + */ + @GET + @Path("view") + @Produces({MediaType.APPLICATION_JSON}) + public Response getUser(@QueryParam("username") String username) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + if (userStoreManager.isExistingUser(username)) { + UserWrapper user = new UserWrapper(); + user.setUsername(username); + user.setEmailAddress(getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS)); + user.setFirstname(getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + user.setLastname(getClaimValue(username, Constants.USER_CLAIM_LAST_NAME)); + // Outputting debug message upon successful retrieval of user + if (log.isDebugEnabled()) { + log.debug("User by username: " + username + " was found."); + } + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("User information was retrieved successfully."); + responsePayload.setResponseContent(user); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } else { + // Outputting debug message upon trying to remove non-existing user + if (log.isDebugEnabled()) { + log.debug("User by username: " + username + " does not exist."); + } + // returning response with bad request state + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer( + "User by username: " + username + " does not exist."); + return Response.status(HttpStatus.SC_NOT_FOUND).entity(responsePayload).build(); + } + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to retrieve user by username: " + username; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + + /** + * Update user in user store + * + * @param userWrapper Wrapper object representing input json payload + * @return {Response} Status of the request wrapped inside Response object + * @throws MDMAPIException + */ + @PUT + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response updateUser(UserWrapper userWrapper, @QueryParam("username") String username) + throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + if (userStoreManager.isExistingUser(userWrapper.getUsername())) { + Map defaultUserClaims = + buildDefaultUserClaims(userWrapper.getFirstname(), userWrapper.getLastname(), + userWrapper.getEmailAddress()); + if (StringUtils.isNotEmpty(userWrapper.getPassword())) { + // Decoding Base64 encoded password + byte[] decodedBytes = Base64.decodeBase64(userWrapper.getPassword()); + userStoreManager.updateCredentialByAdmin(userWrapper.getUsername(), + new String(decodedBytes, "UTF-8")); + log.debug("User credential of username: " + userWrapper.getUsername() + " has been changed"); + } + List listofFilteredRoles = getFilteredRoles(userStoreManager, userWrapper.getUsername()); + final String[] existingRoles = listofFilteredRoles.toArray(new String[listofFilteredRoles.size()]); + + /* + Use the Set theory to find the roles to delete and roles to add + The difference of roles in existingRolesSet and newRolesSet needed to be deleted + new roles to add = newRolesSet - The intersection of roles in existingRolesSet and newRolesSet + */ + final TreeSet existingRolesSet = new TreeSet(); + Collections.addAll(existingRolesSet, existingRoles); + final TreeSet newRolesSet = new TreeSet(); + Collections.addAll(newRolesSet, userWrapper.getRoles()); + existingRolesSet.removeAll(newRolesSet); + // Now we have the roles to delete + String[] rolesToDelete = existingRolesSet.toArray(new String[existingRolesSet.size()]); + List roles = new ArrayList(Arrays.asList(rolesToDelete)); + roles.remove(ROLE_EVERYONE); + rolesToDelete = roles.toArray(new String[0]); + // Clearing and re-initializing the set + existingRolesSet.clear(); + Collections.addAll(existingRolesSet, existingRoles); + newRolesSet.removeAll(existingRolesSet); + // Now we have the roles to add + String[] rolesToAdd = newRolesSet.toArray(new String[newRolesSet.size()]); + userStoreManager.updateRoleListOfUser(userWrapper.getUsername(), rolesToDelete, rolesToAdd); + userStoreManager.setUserClaimValues(userWrapper.getUsername(), defaultUserClaims, null); + // Outputting debug message upon successful addition of user + if (log.isDebugEnabled()) { + log.debug("User by username: " + userWrapper.getUsername() + " was successfully updated."); + } + // returning response with success state + responsePayload.setStatusCode(HttpStatus.SC_CREATED); + responsePayload.setMessageFromServer("User by username: " + userWrapper.getUsername() + + " was successfully updated."); + return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); + } else { + if (log.isDebugEnabled()) { + log.debug("User by username: " + userWrapper.getUsername() + + " doesn't exists. Therefore, request made to update user was refused."); + } + // returning response with bad request state + responsePayload.setStatusCode(HttpStatus.SC_CONFLICT); + responsePayload. + setMessageFromServer("User by username: " + userWrapper.getUsername() + + " doesn't exists. Therefore, request made to update user was refused."); + return Response.status(HttpStatus.SC_CONFLICT).entity(responsePayload).build(); + } + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to update user by username: " + userWrapper.getUsername(); + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } catch (UnsupportedEncodingException e) { + String errorMsg = "Exception in trying to update user by username: " + userWrapper.getUsername(); + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + + /** + * Private method to be used by addUser() to + * generate an initial user password for a user. + * This will be the password used by a user for his initial login to the system. + * + * @return {string} Initial User Password + */ + private String generateInitialUserPassword() { + int passwordLength = 6; + //defining the pool of characters to be used for initial password generation + String lowerCaseCharset = "abcdefghijklmnopqrstuvwxyz"; + String upperCaseCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + String numericCharset = "0123456789"; + Random randomGenerator = new Random(); + String totalCharset = lowerCaseCharset + upperCaseCharset + numericCharset; + int totalCharsetLength = totalCharset.length(); + StringBuffer initialUserPassword = new StringBuffer(); + for (int i = 0; i < passwordLength; i++) { + initialUserPassword + .append(totalCharset.charAt(randomGenerator.nextInt(totalCharsetLength))); + } + if (log.isDebugEnabled()) { + log.debug("Initial user password is created for new user: " + initialUserPassword); + } + return initialUserPassword.toString(); + } + + /** + * Method to build default user claims. + * + * @param firstname First name of the user + * @param lastname Last name of the user + * @param emailAddress Email address of the user + * @return {Object} Default user claims to be provided + */ + private Map buildDefaultUserClaims(String firstname, String lastname, String emailAddress) { + Map defaultUserClaims = new HashMap(); + defaultUserClaims.put(Constants.USER_CLAIM_FIRST_NAME, firstname); + defaultUserClaims.put(Constants.USER_CLAIM_LAST_NAME, lastname); + defaultUserClaims.put(Constants.USER_CLAIM_EMAIL_ADDRESS, emailAddress); + if (log.isDebugEnabled()) { + log.debug("Default claim map is created for new user: " + defaultUserClaims.toString()); + } + return defaultUserClaims; + } + + /** + * Method to remove user from emm-user-store. + * + * @param username Username of the user + * @return {Response} Status of the request wrapped inside Response object + * @throws MDMAPIException + */ + @DELETE + @Produces({MediaType.APPLICATION_JSON}) + public Response removeUser(@QueryParam("username") String username) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + if (userStoreManager.isExistingUser(username)) { + // if user already exists, trying to remove user + userStoreManager.deleteUser(username); + // Outputting debug message upon successful removal of user + if (log.isDebugEnabled()) { + log.debug("User by username: " + username + " was successfully removed."); + } + // returning response with success state + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer( + "User by username: " + username + " was successfully removed."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } else { + // Outputting debug message upon trying to remove non-existing user + if (log.isDebugEnabled()) { + log.debug("User by username: " + username + " does not exist for removal."); + } + // returning response with bad request state + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer( + "User by username: " + username + " does not exist for removal."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to remove user by username: " + username; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + + /** + * get all the roles except for the internal/xxx and application/xxx + * + * @param userStoreManager + * @param username + * @return the list of filtered roles + * @throws UserStoreException + */ + private List getFilteredRoles(UserStoreManager userStoreManager, String username) + throws UserStoreException { + String[] roleListOfUser = userStoreManager.getRoleListOfUser(username); + List filteredRoles = new ArrayList(); + for (String role : roleListOfUser) { + if (!(role.startsWith("Internal/") || role.startsWith("Application/"))) { + filteredRoles.add(role); + } + } + return filteredRoles; + } + + /** + * Get user's roles by username + * + * @param username Username of the user + * @return {Response} Status of the request wrapped inside Response object + * @throws MDMAPIException + */ + @GET + @Path("roles") + @Produces({MediaType.APPLICATION_JSON}) + public Response getRoles(@QueryParam("username") String username) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + if (userStoreManager.isExistingUser(username)) { + responsePayload.setResponseContent(Arrays.asList(getFilteredRoles(userStoreManager, username))); + // Outputting debug message upon successful removal of user + if (log.isDebugEnabled()) { + log.debug("User by username: " + username + " was successfully removed."); + } + // returning response with success state + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer( + "User roles obtained for user " + username); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } else { + // Outputting debug message upon trying to remove non-existing user + if (log.isDebugEnabled()) { + log.debug("User by username: " + username + " does not exist for role retrieval."); + } + // returning response with bad request state + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer( + "User by username: " + username + " does not exist for role retrieval."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to retrieve roles for user by username: " + username; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + + /** + * Get the list of all users with all user-related info. + * + * @return A list of users + * @throws MDMAPIException + */ + @GET + @Produces({MediaType.APPLICATION_JSON}) + public Response getAllUsers() throws MDMAPIException { + if (log.isDebugEnabled()) { + log.debug("Getting the list of users with all user-related information"); + } + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ArrayList userList; + try { + String[] users = userStoreManager.listUsers("*", -1); + userList = new ArrayList(users.length); + UserWrapper user; + for (String username : users) { + user = new UserWrapper(); + user.setUsername(username); + user.setEmailAddress(getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS)); + user.setFirstname(getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + user.setLastname(getClaimValue(username, Constants.USER_CLAIM_LAST_NAME)); + userList.add(user); + } + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of users"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + int count = 0; + if (userList != null) { + count = userList.size(); + } + responsePayload.setMessageFromServer("All users were successfully retrieved. " + + "Obtained user count: " + count); + responsePayload.setResponseContent(userList); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get the list of all users with all user-related info. + * + * @return A list of users + * @throws MDMAPIException + */ + @GET + @Path("{filter}") + @Produces({MediaType.APPLICATION_JSON}) + public Response getMatchingUsers(@PathParam("filter") String filter) throws MDMAPIException { + if (log.isDebugEnabled()) { + log.debug("Getting the list of users with all user-related information using the filter : " + filter); + } + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ArrayList userList; + try { + String[] users = userStoreManager.listUsers(filter + "*", -1); + userList = new ArrayList(users.length); + UserWrapper user; + for (String username : users) { + user = new UserWrapper(); + user.setUsername(username); + user.setEmailAddress(getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS)); + user.setFirstname(getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + user.setLastname(getClaimValue(username, Constants.USER_CLAIM_LAST_NAME)); + userList.add(user); + } + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of users using the filter : " + filter; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + int count = 0; + if (userList != null) { + count = userList.size(); + } + responsePayload.setMessageFromServer("All users were successfully retrieved. " + + "Obtained user count: " + count); + responsePayload.setResponseContent(userList); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get the list of user names in the system. + * + * @return A list of user names. + * @throws MDMAPIException + */ + @GET + @Path("view-users") + public Response getAllUsersByUsername(@QueryParam("username") String userName) throws MDMAPIException { + if (log.isDebugEnabled()) { + log.debug("Getting the list of users by name"); + } + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ArrayList userList; + try { + String[] users = userStoreManager.listUsers("*" + userName + "*", -1); + userList = new ArrayList(users.length); + UserWrapper user; + for (String username : users) { + user = new UserWrapper(); + user.setUsername(username); + user.setEmailAddress(getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS)); + user.setFirstname(getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + user.setLastname(getClaimValue(username, Constants.USER_CLAIM_LAST_NAME)); + userList.add(user); + } + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of users"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + int count = 0; + if (userList != null) { + count = userList.size(); + } + responsePayload.setMessageFromServer("All users by username were successfully retrieved. " + + "Obtained user count: " + count); + responsePayload.setResponseContent(userList); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get the list of user names in the system. + * + * @return A list of user names. + * @throws MDMAPIException + */ + @GET + @Path("users-by-username") + public Response getAllUserNamesByUsername(@QueryParam("username") String userName) throws MDMAPIException { + if (log.isDebugEnabled()) { + log.debug("Getting the list of users by name"); + } + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ArrayList userList; + try { + String[] users = userStoreManager.listUsers("*" + userName + "*", -1); + userList = new ArrayList(users.length); + UserWrapper user; + for (String username : users) { + userList.add(username); + } + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of users"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + int count = 0; + if (userList != null) { + count = userList.size(); + } + responsePayload.setMessageFromServer("All users by username were successfully retrieved. " + + "Obtained user count: " + count); + responsePayload.setResponseContent(userList); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Gets a claim-value from user-store. + * + * @param username Username of the user + * @param claimUri required ClaimUri + * @return A list of usernames + * @throws MDMAPIException, UserStoreException + */ + private String getClaimValue(String username, String claimUri) throws MDMAPIException, UserStoreException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + return userStoreManager.getUserClaimValue(username, claimUri, null); + } + + /** + * Method used to send an invitation email to a new user to enroll a device. + * + * @param username Username of the user + * @throws MDMAPIException, UserStoreException, DeviceManagementException + */ + private void inviteNewlyAddedUserToEnrollDevice(String username, String password) throws + MDMAPIException, + UserStoreException, + DeviceManagementException { + if (log.isDebugEnabled()) { + log.debug("Sending invitation mail to user by username: " + username); + } + String tennentDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + if (tennentDomain.equalsIgnoreCase("carbon.super")) { + tennentDomain = ""; + } + if (!username.contains("/")) { + username = "/" + username; + } + String[] usernameBits = username.split("/"); + DeviceManagementProviderService deviceManagementProviderService = MDMAPIUtils.getDeviceManagementService(); + EmailMessageProperties emailMessageProperties = new EmailMessageProperties(); + emailMessageProperties.setUserName(usernameBits[1]); + emailMessageProperties.setDomainName(tennentDomain); + emailMessageProperties.setFirstName(getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + emailMessageProperties.setPassword(password); + String[] mailAddress = new String[1]; + mailAddress[0] = getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS); + emailMessageProperties.setMailTo(mailAddress); + deviceManagementProviderService.sendRegistrationEmail(emailMessageProperties); + } + + /** + * Method used to send an invitation email to a existing user to enroll a device. + * + * @param usernames Username list of the users to be invited + * @throws MDMAPIException + */ + @POST + @Path("email-invitation") + @Produces({MediaType.APPLICATION_JSON}) + public Response inviteExistingUsersToEnrollDevice(List usernames) throws MDMAPIException { + if (log.isDebugEnabled()) { + log.debug("Sending enrollment invitation mail to existing user."); + } + DeviceManagementProviderService deviceManagementProviderService = MDMAPIUtils.getDeviceManagementService(); + try { + for (int i = 0; i < usernames.size(); i++) { + EmailMessageProperties emailMessageProperties = new EmailMessageProperties(); + emailMessageProperties + .setFirstName(getClaimValue(usernames.get(i), Constants.USER_CLAIM_FIRST_NAME)); + emailMessageProperties.setUserName(usernames.get(i)); + String[] mailAddress = new String[1]; + mailAddress[0] = getClaimValue(usernames.get(i), Constants.USER_CLAIM_EMAIL_ADDRESS); + if (StringUtils.isNotEmpty(mailAddress[0])) { + emailMessageProperties.setMailTo(mailAddress); + deviceManagementProviderService.sendEnrolmentInvitation(emailMessageProperties); + } + } + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to invite user."; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } catch (DeviceManagementException e) { + String errorMsg = "Exception in trying to invite user."; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Email invitation was successfully sent to user."); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } + + /** + * Get a list of devices based on the username. + * + * @param username Username of the device owner + * @return A list of devices + * @throws MDMAPIException + */ + @GET + @Produces({MediaType.APPLICATION_JSON}) + @Path("devices") + public Object getAllDeviceOfUser(@QueryParam("username") String username, @QueryParam("start") int startIdx, + @QueryParam("length") int length) + throws MDMAPIException { + DeviceManagementProviderService dmService; + try { + dmService = MDMAPIUtils.getDeviceManagementService(); + if (length > 0) { + PaginationRequest request = new PaginationRequest(startIdx, length); + request.setOwner(username); + return dmService.getDevicesOfUser(request); + } + return dmService.getDevicesOfUser(username); + } catch (DeviceManagementException e) { + String errorMsg = "Device management error"; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + + /** + * This method is used to retrieve the user count of the system. + * + * @return returns the count. + * @throws MDMAPIException + */ + @GET + @Path("count") + public int getUserCount() throws MDMAPIException { + try { + String[] users = MDMAPIUtils.getUserStoreManager().listUsers("*", -1); + if (users == null) { + return 0; + } + return users.length; + } catch (UserStoreException e) { + String msg = + "Error occurred while retrieving the list of users that exist within the current tenant"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + /** + * API is used to update roles of a user + * + * @param username + * @param userList + * @return + * @throws MDMAPIException + */ + @PUT + @Path("{roleName}/users") + @Produces({MediaType.APPLICATION_JSON}) + public Response updateRoles(@PathParam("username") String username, List userList) + throws MDMAPIException { + final UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + try { + if (log.isDebugEnabled()) { + log.debug("Updating the roles of a user"); + } + SetReferenceTransformer transformer = new SetReferenceTransformer(); + transformer.transform(Arrays.asList(userStoreManager.getRoleListOfUser(username)), + userList); + final String[] rolesToAdd = (String[]) + transformer.getObjectsToAdd().toArray(new String[transformer.getObjectsToAdd().size()]); + final String[] rolesToDelete = (String[]) + transformer.getObjectsToRemove().toArray(new String[transformer.getObjectsToRemove().size()]); + + userStoreManager.updateRoleListOfUser(username, rolesToDelete, rolesToAdd); + } catch (UserStoreException e) { + String msg = "Error occurred while saving the roles for user: " + username; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).build(); + } + + /** + * Method to change the user password. + * + * @param credentials Wrapper object representing user credentials. + * @return {Response} Status of the request wrapped inside Response object. + * @throws MDMAPIException + */ + @POST + @Path("reset-password") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response resetPassword(UserCredentialWrapper credentials) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + byte[] decodedNewPassword = Base64.decodeBase64(credentials.getNewPassword()); + userStoreManager.updateCredentialByAdmin(credentials.getUsername(), new String( + decodedNewPassword, "UTF-8")); + responsePayload.setStatusCode(HttpStatus.SC_CREATED); + responsePayload.setMessageFromServer("User password by username: " + credentials.getUsername() + + " was successfully changed."); + return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); + } catch (UserStoreException e) { + String errorMsg = "Exception in trying to change the password by username: " + credentials.getUsername(); + log.error(errorMsg, e); + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer("Old password does not match."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } catch (UnsupportedEncodingException e) { + String errorMsg = "Exception in trying to change the password by username: " + credentials.getUsername(); + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorHandler.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorHandler.java new file mode 100644 index 000000000..da8825b17 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api.common; + +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +@Produces({ "application/json", "application/xml" }) +public class ErrorHandler implements ExceptionMapper { + + public Response toResponse(MDMAPIException exception) { + ErrorMessage errorMessage = new ErrorMessage(); + errorMessage.setErrorMessage(exception.getErrorMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build(); + } +} diff --git a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/APIFaultException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorMessage.java similarity index 63% rename from components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/APIFaultException.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorMessage.java index f04a64f99..7dbe39553 100644 --- a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/APIFaultException.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/ErrorMessage.java @@ -15,26 +15,27 @@ * specific language governing permissions and limitations * under the License. */ +package org.wso2.carbon.mdm.api.common; -package org.wso2.carbon.key.mgt.handler.valve; -public class APIFaultException extends Exception { +public class ErrorMessage { - private static final long serialVersionUID = 1L; - private int errorCode; + private String errorMessage; + private String errorCode; - public APIFaultException(int errorCode, String message) { - super(message); - this.errorCode = errorCode; + public String getErrorMessage() { + return errorMessage; } - public APIFaultException(int errorCode, String message, Throwable cause) { - super(message, cause); - this.errorCode = errorCode; + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; } - public int getErrorCode() { + public String getErrorCode() { return errorCode; } + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/MDMAPIException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/MDMAPIException.java new file mode 100644 index 000000000..4139e56f4 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/common/MDMAPIException.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api.common; + +/** + * Custom exception class for handling CDM API related exceptions. + */ +public class MDMAPIException extends Exception { + + private static final long serialVersionUID = 7950151650447893900L; + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public MDMAPIException(String msg, Exception e) { + super(msg, e); + setErrorMessage(msg); + } + + public MDMAPIException(String msg, Throwable cause) { + super(msg, cause); + setErrorMessage(msg); + } + + public MDMAPIException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public MDMAPIException() { + super(); + } + + public MDMAPIException(Throwable cause) { + super(cause); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/context/DeviceOperationContext.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/context/DeviceOperationContext.java new file mode 100644 index 000000000..aef30c70f --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/context/DeviceOperationContext.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api.context; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +/** + * Model object of DeviceOperation. + */ +@XmlRootElement +public class DeviceOperationContext { + + private List devices; + private Operation operation; + + @XmlElement + public List getDevices() { + return devices; + } + + public void setDevices(List devices) { + this.devices = devices; + } + + @XmlElement + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation operation) { + this.operation = operation; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java new file mode 100644 index 000000000..0c474818a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java @@ -0,0 +1,255 @@ +/* + * 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.wso2.carbon.mdm.api.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfigurationManagementService; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; +import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.ntask.core.TaskManager; +import org.wso2.carbon.policy.mgt.common.PolicyMonitoringTaskException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; +import org.wso2.carbon.policy.mgt.core.task.TaskScheduleService; +import org.wso2.carbon.policy.mgt.core.util.PolicyManagementConstants; +import org.wso2.carbon.user.api.AuthorizationManager; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.api.UserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import java.util.List; + +/** + * MDMAPIUtils class provides utility function used by CDM REST-API classes. + */ +public class MDMAPIUtils { + + private static final String NOTIFIER_FREQUENCY = "notifierFrequency"; + + private static Log log = LogFactory.getLog(MDMAPIUtils.class); + + public static int getNotifierFrequency(TenantConfiguration tenantConfiguration) { + List configEntryList = tenantConfiguration.getConfiguration(); + if (configEntryList != null && !configEntryList.isEmpty()) { + for(ConfigurationEntry entry : configEntryList) { + if (NOTIFIER_FREQUENCY.equals(entry.getName())) { + return Integer.parseInt((String) entry.getValue()); + } + } + } + return 0; + } + + public static void scheduleTaskService(int notifierFrequency) { + TaskScheduleService taskScheduleService; + try { + taskScheduleService = getPolicyManagementService().getTaskScheduleService(); + if (taskScheduleService.isTaskScheduled()) { + taskScheduleService.updateTask(notifierFrequency); + } else { + taskScheduleService.startTask(notifierFrequency); + } + } catch (PolicyMonitoringTaskException e) { + log.error("Exception occurred while starting the Task service.", e); + } + } + + public static DeviceManagementProviderService getDeviceManagementService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceManagementProviderService deviceManagementProviderService = + (DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + if (deviceManagementProviderService == null) { + String msg = "Device Management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + public static int getTenantId(String tenantDomain) throws MDMAPIException { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + RealmService realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + try { + return realmService.getTenantManager().getTenantId(tenantDomain); + } catch (UserStoreException e) { + throw new MDMAPIException( + "Error obtaining tenant id from tenant domain " + tenantDomain); + } + } + + public static UserStoreManager getUserStoreManager() throws MDMAPIException { + RealmService realmService; + UserStoreManager userStoreManager; + try { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + if (realmService == null) { + String msg = "Realm service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + int tenantId = ctx.getTenantId(); + userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager(); + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving current user store manager"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return userStoreManager; + } + + /** + * Getting the current tenant's user realm + * + * @return + * @throws MDMAPIException + */ + public static UserRealm getUserRealm() throws MDMAPIException { + RealmService realmService; + UserRealm realm; + try { + //PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + //ctx.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + //ctx.setTenantId(MultitenantConstants.SUPER_TENANT_ID); + realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + + if (realmService == null) { + String msg = "Realm service not initialized"; + log.error(msg); + throw new MDMAPIException(msg); + } + int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + realm = realmService.getTenantUserRealm(tenantId); + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving current user realm"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } finally { + //PrivilegedCarbonContext.endTenantFlow(); + } + return realm; + } + + public static AuthorizationManager getAuthorizationManager() throws MDMAPIException { + RealmService realmService; + AuthorizationManager authorizationManager; + try { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + if (realmService == null) { + String msg = "Realm service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + int tenantId = ctx.getTenantId(); + authorizationManager = realmService.getTenantUserRealm(tenantId).getAuthorizationManager(); + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving current Authorization manager."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return authorizationManager; + } + + /** + * This method is used to get the current tenant id. + * + * @return returns the tenant id. + */ + public static int getTenantId() { + return CarbonContext.getThreadLocalCarbonContext().getTenantId(); + } + + public static DeviceIdentifier instantiateDeviceIdentifier(String deviceType, String deviceId) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setType(deviceType); + deviceIdentifier.setId(deviceId); + return deviceIdentifier; + } + + public static ApplicationManagementProviderService getAppManagementService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ApplicationManagementProviderService applicationManagementProviderService = + (ApplicationManagementProviderService) ctx.getOSGiService(ApplicationManagementProviderService.class, null); + if (applicationManagementProviderService == null) { + String msg = "Application management service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return applicationManagementProviderService; + } + + public static PolicyManagerService getPolicyManagementService() { + PolicyManagerService policyManagementService; + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + policyManagementService = + (PolicyManagerService) ctx.getOSGiService(PolicyManagerService.class, null); + if (policyManagementService == null) { + String msg = "Policy Management service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return policyManagementService; + } + + public static TenantConfigurationManagementService getTenantConfigurationManagementService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + TenantConfigurationManagementService tenantConfigurationManagementService = + (TenantConfigurationManagementService) ctx.getOSGiService(TenantConfigurationManagementService.class, null); + if (tenantConfigurationManagementService == null) { + String msg = "Tenant configuration Management service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return tenantConfigurationManagementService; + } + + public static NotificationManagementService getNotificationManagementService() { + NotificationManagementService notificationManagementService; + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + notificationManagementService = (NotificationManagementService) ctx.getOSGiService( + NotificationManagementService.class, null); + if (notificationManagementService == null) { + String msg = "Notification Management service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return notificationManagementService; + } + + public static PaginationResult getPagingResponse(int recordsTotal, int recordsFiltered, int draw, List data) { + PaginationResult pagingResponse = new PaginationResult(); + pagingResponse.setRecordsTotal(recordsTotal); + pagingResponse.setRecordsFiltered(recordsFiltered); + pagingResponse.setDraw(draw); + pagingResponse.setData(data); + return pagingResponse; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAndroidOperationUtil.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAndroidOperationUtil.java new file mode 100644 index 000000000..e50fc0bde --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAndroidOperationUtil.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.api.util; + +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.beans.MobileApp; +import org.wso2.carbon.mdm.beans.android.WebApplication; + +/** + * + * This class contains the all the operations related to Android. + */ +public class MDMAndroidOperationUtil { + + /** + * This method is used to create Install Application operation. + * + * @param application MobileApp application + * @return operation + * @throws MDMAPIException + * + */ + public static Operation createInstallAppOperation(MobileApp application) throws MDMAPIException { + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_INSTALL_APPLICATION); + operation.setType(Operation.Type.PROFILE); + + switch (application.getType()) { + case ENTERPRISE: + org.wso2.carbon.mdm.beans.android.EnterpriseApplication enterpriseApplication = + new org.wso2.carbon.mdm.beans.android.EnterpriseApplication(); + enterpriseApplication.setType(application.getType().toString()); + enterpriseApplication.setUrl(application.getLocation()); + operation.setPayLoad(enterpriseApplication.toJSON()); + break; + case PUBLIC: + org.wso2.carbon.mdm.beans.android.AppStoreApplication appStoreApplication = + new org.wso2.carbon.mdm.beans.android.AppStoreApplication(); + appStoreApplication.setType(application.getType().toString()); + appStoreApplication.setAppIdentifier(application.getIdentifier()); + operation.setPayLoad(appStoreApplication.toJSON()); + break; + case WEBAPP: + WebApplication webApplication = new WebApplication(); + webApplication.setUrl(application.getLocation()); + webApplication.setName(application.getName()); + webApplication.setType(application.getType().toString()); + operation.setPayLoad(webApplication.toJSON()); + break; + default: + String errorMessage = "Invalid application type."; + throw new MDMAPIException(errorMessage); + } + return operation; + } + + /** + * This method is used to create Uninstall Application operation. + * @param application MobileApp application + * @return operation + * @throws MDMAPIException + */ + public static Operation createAppUninstallOperation(MobileApp application) throws MDMAPIException { + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(MDMAppConstants.AndroidConstants.OPCODE_UNINSTALL_APPLICATION); + operation.setType(Operation.Type.PROFILE); + + switch (application.getType()) { + case ENTERPRISE: + org.wso2.carbon.mdm.beans.android.EnterpriseApplication enterpriseApplication = + new org.wso2.carbon.mdm.beans.android.EnterpriseApplication(); + enterpriseApplication.setType(application.getType().toString()); + enterpriseApplication.setAppIdentifier(application.getAppIdentifier()); + operation.setPayLoad(enterpriseApplication.toJSON()); + break; + case PUBLIC: + org.wso2.carbon.mdm.beans.android.AppStoreApplication appStoreApplication = + new org.wso2.carbon.mdm.beans.android.AppStoreApplication(); + appStoreApplication.setType(application.getType().toString()); + appStoreApplication.setAppIdentifier(application.getAppIdentifier()); + operation.setPayLoad(appStoreApplication.toJSON()); + break; + case WEBAPP: + WebApplication webApplication = new WebApplication(); + webApplication.setUrl(application.getLocation()); + webApplication.setName(application.getName()); + webApplication.setType(application.getType().toString()); + operation.setPayLoad(webApplication.toJSON()); + break; + default: + String errorMessage = "Invalid application type."; + throw new MDMAPIException(errorMessage); + } + return operation; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAppConstants.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAppConstants.java new file mode 100644 index 000000000..a4a7f6071 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAppConstants.java @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.mdm.api.util; + +/** + * This class holds all the constants used for IOS and Android. + */ +public class MDMAppConstants { + + public class IOSConstants { + + private IOSConstants() { + throw new AssertionError(); + } + public static final String IS_REMOVE_APP = "isRemoveApp"; + public static final String IS_PREVENT_BACKUP = "isPreventBackup"; + public static final String I_TUNES_ID = "iTunesId"; + public static final String LABEL = "label"; + public static final String OPCODE_INSTALL_ENTERPRISE_APPLICATION = "INSTALL_ENTERPRISE_APPLICATION"; + public static final String OPCODE_INSTALL_STORE_APPLICATION = "INSTALL_STORE_APPLICATION"; + public static final String OPCODE_INSTALL_WEB_APPLICATION = "WEB_CLIP"; + public static final String OPCODE_REMOVE_APPLICATION = "REMOVE_APPLICATION"; + } + + public class AndroidConstants { + + private AndroidConstants() { + throw new AssertionError(); + } + public static final String OPCODE_INSTALL_APPLICATION = "INSTALL_APPLICATION"; + public static final String OPCODE_UNINSTALL_APPLICATION = "UNINSTALL_APPLICATION"; + } + + public class RegistryConstants { + + private RegistryConstants() { + throw new AssertionError(); + } + public static final String GENERAL_CONFIG_RESOURCE_PATH = "general"; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMIOSOperationUtil.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMIOSOperationUtil.java new file mode 100644 index 000000000..261555d33 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMIOSOperationUtil.java @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.mdm.api.util; + +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.beans.MobileApp; +import org.wso2.carbon.mdm.beans.ios.WebClip; + +import java.util.Properties; + +/** + * This class contains the all the operations related to IOS. + */ +public class MDMIOSOperationUtil { + + /** + * This method is used to create Install Application operation. + * + * @param application MobileApp application + * @return operation + * @throws MDMAPIException + * + */ + public static Operation createInstallAppOperation(MobileApp application) throws MDMAPIException { + + ProfileOperation operation = new ProfileOperation(); + + switch (application.getType()) { + case ENTERPRISE: + org.wso2.carbon.mdm.beans.ios.EnterpriseApplication enterpriseApplication = + new org.wso2.carbon.mdm.beans.ios.EnterpriseApplication(); + enterpriseApplication.setBundleId(application.getId()); + enterpriseApplication.setIdentifier(application.getIdentifier()); + enterpriseApplication.setManifestURL(application.getLocation()); + + Properties properties = application.getProperties(); + enterpriseApplication.setPreventBackupOfAppData((Boolean) properties. + get(MDMAppConstants.IOSConstants.IS_PREVENT_BACKUP)); + enterpriseApplication.setRemoveAppUponMDMProfileRemoval((Boolean) properties. + get(MDMAppConstants.IOSConstants.IS_REMOVE_APP)); + operation.setCode(MDMAppConstants.IOSConstants.OPCODE_INSTALL_ENTERPRISE_APPLICATION); + operation.setPayLoad(enterpriseApplication.toJSON()); + operation.setType(Operation.Type.COMMAND); + break; + case PUBLIC: + org.wso2.carbon.mdm.beans.ios.AppStoreApplication appStoreApplication = + new org.wso2.carbon.mdm.beans.ios.AppStoreApplication(); + appStoreApplication.setRemoveAppUponMDMProfileRemoval((Boolean) application.getProperties(). + get(MDMAppConstants.IOSConstants.IS_REMOVE_APP)); + appStoreApplication.setIdentifier(application.getIdentifier()); + appStoreApplication.setPreventBackupOfAppData((Boolean) application.getProperties(). + get(MDMAppConstants.IOSConstants.IS_PREVENT_BACKUP)); + appStoreApplication.setBundleId(application.getId()); + appStoreApplication.setiTunesStoreID((Integer) application.getProperties(). + get(MDMAppConstants.IOSConstants.I_TUNES_ID)); + operation.setCode(MDMAppConstants.IOSConstants.OPCODE_INSTALL_STORE_APPLICATION); + operation.setType(Operation.Type.COMMAND); + operation.setPayLoad(appStoreApplication.toJSON()); + break; + case WEBAPP: + WebClip webClip = new WebClip(); + webClip.setIcon(application.getIconImage()); + webClip.setIsRemovable(application.getProperties(). + getProperty(MDMAppConstants.IOSConstants.IS_REMOVE_APP)); + webClip.setLabel(application.getProperties(). + getProperty(MDMAppConstants.IOSConstants.LABEL)); + webClip.setURL(application.getLocation()); + + operation.setCode(MDMAppConstants.IOSConstants.OPCODE_INSTALL_WEB_APPLICATION); + operation.setType(Operation.Type.PROFILE); + operation.setPayLoad(webClip.toJSON()); + break; + } + return operation; + } + + public static Operation createAppUninstallOperation(MobileApp application) throws MDMAPIException{ + + ProfileOperation operation = new ProfileOperation(); + operation.setCode(MDMAppConstants.IOSConstants.OPCODE_REMOVE_APPLICATION); + operation.setType(Operation.Type.PROFILE); + + org.wso2.carbon.mdm.beans.ios.RemoveApplication removeApplication = + new org.wso2.carbon.mdm.beans.ios.RemoveApplication(); + removeApplication.setBundleId(application.getIdentifier()); + operation.setPayLoad(removeApplication.toJSON()); + + return operation; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java new file mode 100644 index 000000000..8cc7d3591 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java @@ -0,0 +1,106 @@ +/* + * 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.wso2.carbon.mdm.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; + + @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 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); + } + + 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/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ApplicationWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ApplicationWrapper.java new file mode 100644 index 000000000..ad2db850d --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ApplicationWrapper.java @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import java.util.List; + +public class ApplicationWrapper { + + private List userNameList; + private List roleNameList; + private List deviceIdentifiers; + private MobileApp application; + + public MobileApp getApplication() { + return application; + } + + public void setApplication(MobileApp application) { + this.application = application; + } + public List getUserNameList() { + return userNameList; + } + + public void setUserNameList(List userNameList) { + this.userNameList = userNameList; + } + + public List getRoleNameList() { + return roleNameList; + } + + public void setRoleNameList(List roleNameList) { + this.roleNameList = roleNameList; + } + + public List getDeviceIdentifiers() { + return deviceIdentifiers; + } + + public void setDeviceIdentifiers(List deviceIdentifiers) { + this.deviceIdentifiers = deviceIdentifiers; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileApp.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileApp.java new file mode 100644 index 000000000..2f1ef19b3 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileApp.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * This class represents the generic mobile Application information + * which is used by AppM. + */ +public class MobileApp { + + private String id; + private String name; + private MobileAppTypes type; + private String platform; + private String version; + private String identifier; + private String iconImage; + private String packageName; + private String appIdentifier; + private String location; + private Properties properties; + + public MobileAppTypes getType() { + return type; + } + + public void setType(MobileAppTypes type) { + this.type = type; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getIconImage() { + return iconImage; + } + + public void setIconImage(String iconImage) { + this.iconImage = iconImage; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getAppIdentifier() { + return appIdentifier; + } + + public void setAppIdentifier(String appIdentifier) { + this.appIdentifier = appIdentifier; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + this.properties = properties; + } + +} diff --git a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerConstants.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileAppTypes.java similarity index 69% rename from components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerConstants.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileAppTypes.java index dac164659..151f57c5f 100644 --- a/components/key-mgt/org.wso2.carbon.key.mgt.handler.valve/src/main/java/org/wso2/carbon/key/mgt/handler/valve/HandlerConstants.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/MobileAppTypes.java @@ -15,14 +15,8 @@ * specific language governing permissions and limitations * under the License. */ +package org.wso2.carbon.mdm.beans; -package org.wso2.carbon.key.mgt.handler.valve; - -public class HandlerConstants { - - public static final String HEADER_AUTHORIZATION = "Authorization"; - public static final String TOKEN_NAME_BEARER = "Bearer"; - - public static final String NO_MATCHING_AUTH_SCHEME = "noMatchedAuthScheme"; - +public enum MobileAppTypes { + ENTERPRISE,WEBAPP,PUBLIC } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PolicyWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PolicyWrapper.java new file mode 100644 index 000000000..931f98a86 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PolicyWrapper.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans; + +import org.wso2.carbon.device.mgt.common.Device; +import java.util.List; + +public class PolicyWrapper { + + private int id; + private Profile profile; + private String policyName; + private String description; + private String compliance; + private List roles; + private String ownershipType; + private List devices; + private List users; + private int tenantId; + private int profileId; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Profile getProfile() { + return profile; + } + + public void setProfile(Profile profile) { + this.profile = profile; + } + + public String getCompliance() { + return compliance; + } + + public void setCompliance(String compliance) { + this.compliance = compliance; + } + + public String getPolicyName() { + return policyName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setPolicyName(String policyName) { + this.policyName = policyName; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public String getOwnershipType() { + return ownershipType; + } + + public void setOwnershipType(String ownershipType) { + this.ownershipType = ownershipType; + } + + public List getDevices() { + return devices; + } + + public void setDevices(List devices) { + this.devices = devices; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + + public int getProfileId() { + return profileId; + } + + public void setProfileId(int profileId) { + this.profileId = profileId; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PriorityUpdatedPolicyWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PriorityUpdatedPolicyWrapper.java new file mode 100644 index 000000000..ed0b7c56e --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/PriorityUpdatedPolicyWrapper.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans; + +public class PriorityUpdatedPolicyWrapper { + + private int id; + private int priority; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/Profile.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/Profile.java new file mode 100644 index 000000000..19e41d885 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/Profile.java @@ -0,0 +1,107 @@ +/* +* Copyright (c) 2015 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.wso2.carbon.mdm.beans; + + + +import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.sql.Timestamp; +import java.util.List; + +@XmlRootElement +public class Profile { + + private int profileId; + private String profileName; + private int tenantId; + private DeviceType deviceType; + private Timestamp createdDate; + private Timestamp updatedDate; + private List profileFeaturesList; // Features included in the policies. + + public DeviceType getDeviceType() { + return deviceType; + } + + public void setDeviceType(DeviceType deviceType) { + this.deviceType = deviceType; + } + @XmlElement + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + +/* public List getFeaturesList() { + return featuresList; + } + + public void setFeaturesList(List featuresList) { + this.featuresList = featuresList; + }*/ + @XmlElement + public int getProfileId() { + return profileId; + } + + public void setProfileId(int profileId) { + this.profileId = profileId; + } + + @XmlElement + public String getProfileName() { + return profileName; + } + + public void setProfileName(String profileName) { + this.profileName = profileName; + } + + @XmlElement + public Timestamp getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Timestamp createdDate) { + this.createdDate = createdDate; + } + + @XmlElement + public Timestamp getUpdatedDate() { + return updatedDate; + } + + public void setUpdatedDate(Timestamp updatedDate) { + this.updatedDate = updatedDate; + } + + @XmlElement + public List getProfileFeaturesList() { + return profileFeaturesList; + } + + public void setProfileFeaturesList(List profileFeaturesList) { + this.profileFeaturesList = profileFeaturesList; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ProfileFeature.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ProfileFeature.java new file mode 100644 index 000000000..0d56de090 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ProfileFeature.java @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2015 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.wso2.carbon.mdm.beans; + +import com.google.gson.Gson; +import java.io.Serializable; +import java.util.LinkedHashMap; + +public class ProfileFeature implements Serializable { + + private int id; + private String featureCode; + private int profileId; + private int deviceTypeId; + private Object content; + private String payLoad; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFeatureCode() { + return featureCode; + } + + public void setFeatureCode(String featureCode) { + this.featureCode = featureCode; + } + + public int getProfileId() { + return profileId; + } + + public void setProfileId(int profileId) { + this.profileId = profileId; + } + + public int getDeviceTypeId() { + return deviceTypeId; + } + + public void setDeviceTypeId(int deviceTypeId) { + this.deviceTypeId = deviceTypeId; + } + + + public String getPayLoad() { + Gson gson = new Gson(); + this.payLoad = gson.toJson(content); + return payLoad; + } + + public void setPayLoad(String payLoad) { + this.payLoad = payLoad; + } + + + public Object getContent() { + return content; + } + + public void setContent(Object content) { + this.content = content; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/RoleWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/RoleWrapper.java new file mode 100644 index 000000000..c87640a7c --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/RoleWrapper.java @@ -0,0 +1,59 @@ +package org.wso2.carbon.mdm.beans; + +import org.wso2.carbon.user.mgt.common.UIPermissionNode; + +/* + * Copyright (c) 2015, 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. + */ +public class RoleWrapper { + private String roleName; + private String[] permissions; + private String[] users; + private UIPermissionNode permissionList; + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + + public String[] getPermissions() { + return permissions; + } + + public void setPermissions(String[] permissions) { + this.permissions = permissions; + } + + public String[] getUsers() { + return users; + } + + public void setUsers(String[] users) { + this.users = users; + } + + public UIPermissionNode getPermissionList() { + return permissionList; + } + + public void setPermissionList(UIPermissionNode permissionList) { + this.permissionList = permissionList; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserCredentialWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserCredentialWrapper.java new file mode 100644 index 000000000..91e2fd0ff --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserCredentialWrapper.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans; + +public class UserCredentialWrapper { + + private String username; + /* + Base64 encoded password + */ + private String oldPassword; + private String newPassword; + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getOldPassword() { + return oldPassword; + } + + public void setOldPassword(String oldPassword) { + this.oldPassword = oldPassword; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java new file mode 100644 index 000000000..0e4778d23 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans; + +public class UserWrapper { + + private String username; + /* + Base64 encoded password + */ + private String password; + private String firstname; + private String lastname; + private String emailAddress; + private String[] roles; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getEmailAddress() { + return emailAddress; + } + + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + + /* + Giving a clone of the array since arrays are mutable + */ + public String[] getRoles() { + String[] copiedRoles = roles; + if (roles != null){ + copiedRoles = roles.clone(); + } + return copiedRoles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/AppStoreApplication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/AppStoreApplication.java new file mode 100644 index 000000000..b60ff7cdb --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/AppStoreApplication.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.mdm.beans.android; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; +import java.io.Serializable; + +/** + * This class represents the Appstore Application information. + */ +public class AppStoreApplication implements Serializable { + + private String type; + private String appIdentifier; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAppIdentifier() { + return appIdentifier; + } + + public void setAppIdentifier(String appIdentifier) { + this.appIdentifier = appIdentifier; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/EnterpriseApplication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/EnterpriseApplication.java new file mode 100644 index 000000000..f19dbd44c --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/EnterpriseApplication.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.mdm.beans.android; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; +import java.io.Serializable; + +/** + * This class represents the Enterprise Application information. + */ +public class EnterpriseApplication implements Serializable { + + private String type; + private String url; + private String appIdentifier; + + public String getAppIdentifier() { + return appIdentifier; + } + + public void setAppIdentifier(String appIdentifier) { + this.appIdentifier = appIdentifier; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/WebApplication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/WebApplication.java new file mode 100644 index 000000000..7632524c9 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/android/WebApplication.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed 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.wso2.carbon.mdm.beans.android; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; +import java.io.Serializable; + +/** + * This class represents the Web Application information. + */ +public class WebApplication implements Serializable { + + private String name; + private String url; + private String type; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/AppStoreApplication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/AppStoreApplication.java new file mode 100644 index 000000000..aa6c0a012 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/AppStoreApplication.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans.ios; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; +import java.io.Serializable; + +public class AppStoreApplication implements Serializable { + + private String identifier; + private int iTunesStoreID; + private boolean removeAppUponMDMProfileRemoval; + private boolean preventBackupOfAppData; + private String bundleId; + private String UUID; + + public String getUUID() { + return UUID; + } + + public void setUUID(String UUID) { + this.UUID = UUID; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public int getiTunesStoreID() { + return iTunesStoreID; + } + + public void setiTunesStoreID(int iTunesStoreID) { + this.iTunesStoreID = iTunesStoreID; + } + + public boolean isRemoveAppUponMDMProfileRemoval() { + return removeAppUponMDMProfileRemoval; + } + + public void setRemoveAppUponMDMProfileRemoval(boolean removeAppUponMDMProfileRemoval) { + this.removeAppUponMDMProfileRemoval = removeAppUponMDMProfileRemoval; + } + + public boolean isPreventBackupOfAppData() { + return preventBackupOfAppData; + } + + public void setPreventBackupOfAppData(boolean preventBackupOfAppData) { + this.preventBackupOfAppData = preventBackupOfAppData; + } + + public String getBundleId() { + return bundleId; + } + + public void setBundleId(String bundleId) { + this.bundleId = bundleId; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/EnterpriseApplication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/EnterpriseApplication.java new file mode 100644 index 000000000..d310779fa --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/EnterpriseApplication.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.beans.ios; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; +import java.io.Serializable; + +public class EnterpriseApplication implements Serializable { + + private String identifier; + private String manifestURL; + private boolean removeAppUponMDMProfileRemoval; + private boolean preventBackupOfAppData; + private String bundleId; + private String UUID; + + public void setUUID(String UUID) { + this.UUID = UUID; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getManifestURL() { + return manifestURL; + } + + public void setManifestURL(String manifestURL) { + this.manifestURL = manifestURL; + } + + public boolean isRemoveAppUponMDMProfileRemoval() { + return removeAppUponMDMProfileRemoval; + } + + public void setRemoveAppUponMDMProfileRemoval(boolean removeAppUponMDMProfileRemoval) { + this.removeAppUponMDMProfileRemoval = removeAppUponMDMProfileRemoval; + } + + public boolean isPreventBackupOfAppData() { + return preventBackupOfAppData; + } + + public void setPreventBackupOfAppData(boolean preventBackupOfAppData) { + this.preventBackupOfAppData = preventBackupOfAppData; + } + + public String getBundleId() { + return bundleId; + } + + public void setBundleId(String bundleId) { + this.bundleId = bundleId; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/RemoveApplication.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/RemoveApplication.java new file mode 100644 index 000000000..9c15ba6a3 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/RemoveApplication.java @@ -0,0 +1,24 @@ +package org.wso2.carbon.mdm.beans.ios; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; +import java.io.Serializable; + +public class RemoveApplication implements Serializable { + + private String bundleId; + + public String getBundleId() { + return bundleId; + } + + public void setBundleId(String bundleId) { + this.bundleId = bundleId; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/WebClip.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/WebClip.java new file mode 100644 index 000000000..4604eab46 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/ios/WebClip.java @@ -0,0 +1,60 @@ +package org.wso2.carbon.mdm.beans.ios; + +import com.google.gson.Gson; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import java.io.IOException; + +public class WebClip { + + private String URL; + private String label; + private String icon; + private String isRemovable; + private String UUID; + + public String getUUID() { + return UUID; + } + + public void setUUID(String UUID) { + this.UUID = UUID; + } + + public String getURL() { + return URL; + } + + public void setURL(String URL) { + this.URL = URL; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getIsRemovable() { + return isRemovable; + } + + public void setIsRemovable(String isRemovable) { + this.isRemovable = isRemovable; + } + + public String toJSON() throws MDMAPIException { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/Constants.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/Constants.java new file mode 100644 index 000000000..e9caa31d2 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/Constants.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.util; + +/** + * Holds the constants used by MDM-Admin web application. + */ +public class Constants { + + public static final String USER_CLAIM_EMAIL_ADDRESS = "http://wso2.org/claims/emailaddress"; + public static final String USER_CLAIM_FIRST_NAME = "http://wso2.org/claims/givenname"; + public static final String USER_CLAIM_LAST_NAME = "http://wso2.org/claims/lastname"; + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/MDMUtil.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/MDMUtil.java new file mode 100644 index 000000000..d766776cc --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/MDMUtil.java @@ -0,0 +1,60 @@ +/* + * 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.wso2.carbon.mdm.util; + +import org.wso2.carbon.mdm.beans.ProfileFeature; +import org.wso2.carbon.policy.mgt.common.Profile; + +import java.util.ArrayList; +import java.util.List; + +public class MDMUtil { + + public static Profile convertProfile(org.wso2.carbon.mdm.beans.Profile mdmProfile) { + Profile profile = new Profile(); + profile.setTenantId(mdmProfile.getTenantId()); + profile.setCreatedDate(mdmProfile.getCreatedDate()); + profile.setDeviceType(mdmProfile.getDeviceType()); + + List profileFeatures = + new ArrayList(mdmProfile.getProfileFeaturesList().size()); + for (ProfileFeature mdmProfileFeature : mdmProfile.getProfileFeaturesList()) { + profileFeatures.add(convertProfileFeature(mdmProfileFeature)); + } + profile.setProfileFeaturesList(profileFeatures); + profile.setProfileId(mdmProfile.getProfileId()); + profile.setProfileName(mdmProfile.getProfileName()); + profile.setUpdatedDate(mdmProfile.getUpdatedDate()); + return profile; + } + + public static org.wso2.carbon.policy.mgt.common.ProfileFeature convertProfileFeature(ProfileFeature + mdmProfileFeature) { + + org.wso2.carbon.policy.mgt.common.ProfileFeature profileFeature = + new org.wso2.carbon.policy.mgt.common.ProfileFeature(); + profileFeature.setProfileId(mdmProfileFeature.getProfileId()); + profileFeature.setContent(mdmProfileFeature.getPayLoad()); + profileFeature.setDeviceTypeId(mdmProfileFeature.getDeviceTypeId()); + profileFeature.setFeatureCode(mdmProfileFeature.getFeatureCode()); + profileFeature.setId(mdmProfileFeature.getId()); + return profileFeature; + + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/SetReferenceTransformer.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/SetReferenceTransformer.java new file mode 100644 index 000000000..da4136593 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/util/SetReferenceTransformer.java @@ -0,0 +1,60 @@ +/* + * 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.wso2.carbon.mdm.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeSet; + +public class SetReferenceTransformer{ + private List objectsToRemove; + private List objectsToAdd; + + /** + * Use the Set theory to find the objects to delete and objects to add + + The difference of objects in existingSet and newSet needed to be deleted + + new roles to add = newSet - The intersection of roles in existingSet and newSet + * @param currentList + * @param nextList + */ + public void transform(List currentList, List nextList){ + TreeSet existingSet = new TreeSet(currentList); + TreeSet newSet = new TreeSet(nextList); + + existingSet.removeAll(newSet); + + objectsToRemove = new ArrayList(existingSet); + + // Clearing and re-initializing the set + existingSet = new TreeSet(currentList); + + newSet.removeAll(existingSet); + objectsToAdd = new ArrayList(newSet); + } + + public List getObjectsToRemove() { + return objectsToRemove; + } + + public List getObjectsToAdd() { + return objectsToAdd; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/Application.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/Application.java new file mode 100644 index 000000000..0a11ad1bc --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/Application.java @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2015, 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.wso2.mdm.common; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; + +import java.util.List; + +public class Application { + + private String applicationName; + private String appId; + private String locationUrl; + private String imageUrl; + private String platform; + private String version; + private List userNameList; + private List roleNameList; + + public List getDeviceIdentifiers() { + return deviceIdentifiers; + } + + public void setDeviceIdentifiers(List deviceIdentifiers) { + this.deviceIdentifiers = deviceIdentifiers; + } + + private List deviceIdentifiers; + + + public String getApplicationName() { + return applicationName; + } + + public void setApplicationName(String applicationName) { + this.applicationName = applicationName; + } + + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + + public String getLocationUrl() { + return locationUrl; + } + + public void setLocationUrl(String locationUrl) { + this.locationUrl = locationUrl; + } + + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + + public List getUserNameList() { + return userNameList; + } + + public void setUserNameList(List userNameList) { + this.userNameList = userNameList; + } + + + public List getRoleNameList() { + return roleNameList; + } + + public void setRoleNameList(List roleNameList) { + this.roleNameList = roleNameList; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/GsonMessageBodyHandler.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/GsonMessageBodyHandler.java new file mode 100644 index 000000000..09b49e6f1 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/mdm/common/GsonMessageBodyHandler.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, 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.wso2.mdm.common; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +@Provider +@Produces(APPLICATION_JSON) +@Consumes(APPLICATION_JSON) +public class GsonMessageBodyHandler implements MessageBodyWriter, MessageBodyReader { + + private Gson gson; + private static final String UTF_8 = "UTF-8"; + + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return true; + } + + private Gson getGson() { + if (gson == null) { + final GsonBuilder gsonBuilder = new GsonBuilder(); + gson = gsonBuilder.create(); + } + return gson; + } + + public Object readFrom(Class objectClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap stringStringMultivaluedMap, InputStream entityStream) + throws IOException, WebApplicationException { + + InputStreamReader reader = new InputStreamReader(entityStream, "UTF-8"); + + try { + return getGson().fromJson(reader, type); + } finally { + reader.close(); + } + } + + public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return true; + } + + public long getSize(Object o, Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return -1; + } + + public void writeTo(Object object, Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap stringObjectMultivaluedMap, OutputStream entityStream) + throws IOException, WebApplicationException { + + OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8); + try { + Type jsonType = null; + if (type.equals(type)) { + jsonType = type; + } + getGson().toJson(object, jsonType, writer); + } finally { + writer.close(); + } + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..0e11fe9ba --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,565 @@ + + + + + + + + + Get all devices + /device-mgt/devices/list + /devices + GET + emm_admin + + + + Get all device types + /device-mgt/devices/types + /devices/types + GET + emm_admin + + + + View device + /device-mgt/devices/view + /devices/view + GET + emm_admin + + + + Get device + /device-mgt/devices/view + /devices/*/* + GET + emm_admin,emm_user + + + + Get users' devices + /device-mgt/devices/view + /devices/user/*/* + GET + emm_admin,emm_user + + + + Get device count + /device-mgt/devices/count + /devices/count + GET + emm_admin + + + + Get all users' devices + /device-mgt/devices/list + /devices/name/*/* + GET + emm_admin,emm_user + + + + + + Get all notifications + /device-mgt/notifications/view + /notifications + GET + emm_admin + + + + Add notification + /device-mgt/notifications/add + /notifications + POST + emm_admin + + + + Update notification + /device-mgt/notifications/view + /notifications/*/* + PUT + emm_admin + + + + Get new notifications + /device-mgt/notifications/view + /notifications/* + GET + emm_admin + + + + + + Get all operations + /device-mgt/operations/view + /operations + GET + emm_admin + + + + Add Operation + /device-mgt/operations/add + /operations + POST + emm_admin + + + + Install Application + /device-mgt/operations/application/install + /operations/installApp/* + POST + emm_admin,emm_user + + + + Uninstall Application + /device-mgt/operations/application/uninstall + /operations/uninstallApp/* + POST + emm_admin,emm_user + + + + Get Applications For Devices + /device-mgt/operations/application/view + /operations/*/*/* + GET + emm_admin,emm_user + + + Get Device Operations + /device-mgt/operations/view + /operations/*/* + GET + emm_admin,emm_user + + + + Get Applications For Device Type + /device-mgt/operations/application/view + /operations/* + GET + emm_admin,emm_user + + + + + + Get features + /device-mgt/features/view + /features/* + GET + emm_admin + + + Get all features + /device-mgt/features/view + /features + GET + emm_admin + + + + + + Get all roles + /device-mgt/roles + /roles + GET + emm_admin + + + Get role permissions + /device-mgt/roles + /roles/permissions + GET + emm_admin + + + Get User roles + /device-mgt/roles + /roles/* + GET + emm_admin + + + Update User roles + /device-mgt/roles/update + /roles + PUT + emm_admin + + + Update a specific role + /device-mgt/roles/update + /roles/* + PUT + emm_admin + + + Update User roles + /device-mgt/roles + /roles/*/users + PUT + emm_admin + + + Save User roles + /device-mgt/roles/add + /roles + POST + emm_admin + + + Delete User roles + /device-mgt/roles/delete + /roles + DELETE + emm_admin + + + + + + Get all users + /device-mgt/users/view + /users + GET + emm_admin + + + Add user + /device-mgt/users/add + /users + POST + emm_admin + + + Get user + /device-mgt/users/view + /users/view + GET + emm_admin + + + Update user + /device-mgt/users/update + /users + PUT + emm_admin + + + Change user password + /device-mgt/users/reset-password + /users/reset-password + POST + emm_admin + + + Delete user + /device-mgt/users/delete + /users + DELETE + emm_admin + + + Get user roles by name + /device-mgt/users/roles + /users/roles + GET + emm_admin + + + Get user roles by name + /device-mgt/users/roles + /roles + GET + emm_admin + + + Save Roles + /device-mgt/users/roles + /roles + POST + emm_admin + + + Get all devices of user + /device-mgt/users/devices + /users/devices + GET + emm_admin + + + Get user roles + /device-mgt/users/roles + /users/*/* + GET + emm_admin + + + Get user count + /device-mgt/users/view + /users/count + GET + emm_admin + + + Get all user names + /device-mgt/users/view + /users/view-users + GET + emm_admin + + + Get all usernames + /device-mgt/users/view + /users/users-by-username + GET + emm_admin + + + Get filtered usernames + /device-mgt/users/view + /users/users-by-username/* + GET + emm_admin + + + Send invitation + /device-mgt/users/invite + /users/email-invitation + POST + emm_admin + + + + + + Add Policy + /device-mgt/policies/add + /policies/inactive-policy + POST + emm_admin + + + Get Policy For Device + /device-mgt/policies/view + /policies/*/* + POST + emm_admin + + + Get Policy For Device By Type + /device-mgt/policies/view + /policies/*/*/* + GET + emm_admin + + + Add Active Policy + /device-mgt/policies/add + /policies/active-policy + POST + emm_admin + + + Bulk Policy Removal + /device-mgt/policies/bulk-remove + /policies/bulk-remove + POST + emm_admin + + + Get Policies + /device-mgt/policies/view + /policies + GET + emm_admin + + + Get Policy + /device-mgt/policies/view + /policies/* + GET + emm_admin + + + Update Policy + /device-mgt/policies/update + /policies/* + PUT + emm_admin + + + Delete Policy + /device-mgt/policies/delete + /policies + DELETE + emm_admin + + + Policy Count + /device-mgt/policies/view + /policies/count + GET + emm_admin + + + Policy priorities + /device-mgt/policies/update + /policies/priorities + PUT + emm_admin + + + Activate Policy + /device-mgt/policies/update + /policies/activate + PUT + emm_admin + + + Inactivate Policy + /device-mgt/policies/update + /policies/inactivate + PUT + emm_admin + + + Apply Policy changes + /device-mgt/policies/update + /policies/apply-changes + PUT + emm_admin + + + Start Task + /device-mgt/policies/task + /policies/start-task/* + GET + emm_admin + + + Update Task + /device-mgt/policies/task + /policies/update-task/* + GET + emm_admin + + + Stop Task + /device-mgt/policies/task + /policies/stop-task + GET + emm_admin + + + Get Policy Compliance + /device-mgt/policies/compliance + /policies/*/* + GET + emm_admin + + + + + + Add profile + /device-mgt/profiles/add + /profiles + POST + emm_admin + + + Update profile + /device-mgt/profiles/update + /profiles/* + PUT + emm_admin + + + Add profile + /device-mgt/profiles/delete + /profiles/* + DELETE + emm_admin + + + + + + + + + + + + + + + + + + + + + + + Get configuration + /device-mgt/tenant/configuration/view + /configuration + GET + emm_admin + + + Add configuration + /device-mgt/tenant/configuration/modify + /configuration + POST + emm_admin + + + Update configuration + /device-mgt/tenant/configuration/modify + /configuration + PUT + emm_admin + + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/webapp-classloading.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..ed2ed2162 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..dc53a029b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/web.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..1ee664987 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,74 @@ + + + + Admin-Webapp + + JAX-WS/JAX-RS MDM Endpoint + JAX-WS/JAX-RS Servlet + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + CXFServlet + /* + + + 60 + + + + isAdminService + false + + + doAuthentication + true + + + + + + + MDM-Admin + /* + + + CONFIDENTIAL + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/pom.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/pom.xml new file mode 100644 index 000000000..530e3c8b6 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/pom.xml @@ -0,0 +1,62 @@ + + + + + + + + mobile-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.ui + WSO2 Carbon - EMM Server UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/assembly/src.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.hbs new file mode 100644 index 000000000..302cc5e9a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.hbs @@ -0,0 +1,5 @@ +{{unit "cdmf.unit.ui.title" pageTitle="Platform Configuration"}} + +{{#zone "content"}} + {{unit "cdmf.unit.platform.configuration"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.json new file mode 100644 index 000000000..7316b1146 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/pages/cdmf.page.platform.configuration/configuration.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "uri": "/platform-configuration", + "layout": "cdmf.layout.default" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.hbs new file mode 100644 index 000000000..78813761e --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.hbs @@ -0,0 +1,7 @@ +
      + +{{#zone "bottomJs"}} + + {{js "js/operation-bar.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.json new file mode 100644 index 000000000..56a988c76 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/operation-bar.json @@ -0,0 +1,4 @@ +{ + "version": "1.0.0", + "extends": "cdmf.unit.device.operation-bar" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/js/operation-bar.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/js/operation-bar.js new file mode 100644 index 000000000..fe6c85bd0 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/js/operation-bar.js @@ -0,0 +1,195 @@ +/* + * 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. + */ + +/* + * Setting-up global variables. + */ + +var operations = '.wr-operations', + modalPopup = '.wr-modalpopup', + modalPopupContent = modalPopup + ' .modalpopup-content', + navHeight = $('#nav').height(), + headerHeight = $('header').height(), + offset = (headerHeight + navHeight), + deviceSelection = '.device-select', + platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" + }; + +/* + * Function to get selected devices ID's + */ +function getSelectedDeviceIds() { + var deviceIdentifierList = []; + $(deviceSelection).each(function (index) { + var device = $(this); + var deviceId = device.data('deviceid'); + var deviceType = device.data('type'); + deviceIdentifierList.push({ + "id": deviceId, + "type": deviceType + }); + }); + if (deviceIdentifierList.length == 0) { + var thisTable = $(".DTTT_selected").closest('.dataTables_wrapper').find('.dataTable').dataTable(); + thisTable.api().rows().every(function () { + if ($(this.node()).hasClass('DTTT_selected')) { + var deviceId = $(thisTable.api().row(this).node()).data('deviceid'); + var deviceType = $(thisTable.api().row(this).node()).data('devicetype'); + deviceIdentifierList.push({ + "id": deviceId, + "type": deviceType + }); + } + }); + } + + return deviceIdentifierList; +} + +/* + * On operation click function. + * @param selection: Selected operation + */ +function operationSelect(selection) { + var deviceIdList = getSelectedDeviceIds(); + if (deviceIdList == 0) { + $(modalPopupContent).html($("#errorOperations").html()); + } else { + $(modalPopupContent).addClass("operation-data"); + $(modalPopupContent).html($(operations + " .operation[data-operation-code=" + selection + "]").html()); + $(modalPopupContent).data("operation-code", selection); + } + showPopup(); +} + +function getDevicesByTypes(deviceList) { + var deviceTypes = {}; + $.each(deviceList, function (index, item) { + if (!deviceTypes[item.type]) { + deviceTypes[item.type] = []; + } + if (item.type == platformTypeConstants.ANDROID || + item.type == platformTypeConstants.IOS || item.type == platformTypeConstants.WINDOWS) { + deviceTypes[item.type].push(item.id); + } + }); + return deviceTypes; +} + +function unloadOperationBar() { + $("#showOperationsBtn").addClass("hidden"); + $(".wr-operations").html(""); +} + +function loadOperationBar(deviceType) { + var operationBar = $("#operations-bar"); + var operationBarSrc = operationBar.attr("src"); + var platformType = deviceType; + $.template("operations-bar", operationBarSrc, function (template) { + var serviceURL = "/devicemgt_admin/features/" + platformType; + var successCallback = function (data) { + var viewModel = {}; + data = JSON.parse(data).filter(function (current) { + var iconName; + switch (deviceType) { + case platformTypeConstants.ANDROID: + iconName = operationModule.getAndroidIconForFeature(current.code); + current.type = deviceType; + break; + case platformTypeConstants.WINDOWS: + iconName = operationModule.getWindowsIconForFeature(current.code); + break; + case platformTypeConstants.IOS: + iconName = operationModule.getIOSIconForFeature(current.code); + break; + } + + if (iconName) { + current.icon = iconName; + return current; + } + }); + viewModel.features = data; + var content = template(viewModel); + $(".wr-operations").html(content); + }; + invokerUtil.get(serviceURL, successCallback, function (message) { + $(".wr-operations").html(message); + }); + }); +} + +function runOperation(operationName) { + var deviceIdList = getSelectedDeviceIds(); + var list = getDevicesByTypes(deviceIdList); + + var successCallback = function (data) { + if (operationName == "NOTIFICATION") { + $(modalPopupContent).html($("#messageSuccess").html()); + } else { + $(modalPopupContent).html($("#operationSuccess").html()); + } + showPopup(); + }; + var errorCallback = function (data) { + $(modalPopupContent).html($("#errorOperationUnexpected").html()); + showPopup(); + }; + + var payload, serviceEndPoint; + if (list[platformTypeConstants.IOS]) { + payload = operationModule. + generatePayload(platformTypeConstants.IOS, operationName, list[platformTypeConstants.IOS]); + serviceEndPoint = operationModule.getIOSServiceEndpoint(operationName); + } else if (list[platformTypeConstants.ANDROID]) { + payload = operationModule + .generatePayload(platformTypeConstants.ANDROID, operationName, list[platformTypeConstants.ANDROID]); + serviceEndPoint = operationModule.getAndroidServiceEndpoint(operationName); + } else if (list[platformTypeConstants.WINDOWS]) { + payload = operationModule. + generatePayload(platformTypeConstants.WINDOWS, operationName, list[platformTypeConstants.WINDOWS]); + serviceEndPoint = operationModule.getWindowsServiceEndpoint(operationName); + } + if (operationName == "NOTIFICATION") { + var errorMsgWrapper = "#notification-error-msg"; + var errorMsg = "#notification-error-msg span"; + var message = $("#message").val(); + if (!message) { + $(errorMsg).text("Enter a message. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + invokerUtil.post(serviceEndPoint, payload, successCallback, errorCallback); + $(modalPopupContent).removeData(); + hidePopup(); + } + } else { + invokerUtil.post(serviceEndPoint, payload, successCallback, errorCallback); + $(modalPopupContent).removeData(); + hidePopup(); + } +} + +/* + * DOM ready functions. + */ +$(document).ready(function () { + $(operations).show(); +}); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs new file mode 100644 index 000000000..ad8959bf0 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs @@ -0,0 +1,304 @@ +
      + +
      + + +
      +
      + +
      +
      + +
      + Configure +
      +
      +
      + +
      + + + +
      + +
      + + + +
      + +
      + + + +
      + +
      + + + +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + +
      + + Configure +
      +
      +
      + + + +
      +
      + + +
      + +
      + + + +
      + +
      + Configure +
      + +
      + + +
      +
      + +
      + + +
      + +
      +
      + +
      + + +
      + +
      + Install +
      +
      +
      + +
      + + +
      + +
      + + +
      + +
      + Install +
      +
      +
      + +
      + + +
      + +
      + Uninstall +
      +
      +
      + + + +
      +
      + +
      +
      + +
      + Configure +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-ios.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-ios.hbs new file mode 100644 index 000000000..4cb006ef0 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-ios.hbs @@ -0,0 +1,366 @@ +
      + +
      + + +
      +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      +
      + + +
      +
      + + +
      + Install +
      + +
      +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      +
      + + +
      +
      + + +
      + Install +
      +
      +
      + +
      + +
      + +
      + Uninstall +
      +
      +
      + + + +
      + + +
      + +
      + +
      + + +
      + +
      + + +
      + + + +
      + +
      + + + +
      + +
      + + + +
      + +
      + + + +
      + +
      + Configure +
      + + + +
      + + +
      + +
      + + + +
      +
      + +
      +
      + Path Prefix +
      +
      +
      + + + +
      + +
      + + + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + + + +
      +
      + +
      +
      + : +
      +
      +
      + + + +
      + +
      + + + +
      + +
      + + + +
      + +
      + +
      + + +
      +
      + + + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      + Configure +
      + + +
      + +
      + +
      + +
      + +
      AirPlay password +
      + +
      + Configure +
      + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/operations.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/operations.hbs new file mode 100644 index 000000000..e2fcd8f2c --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/operations.hbs @@ -0,0 +1,156 @@ +
      +
      +
      +
      +

      + + + + + Operation cannot be performed ! +

      +

      + Please select a device or a list of devices to perform an operation. +

      + +
      + Ok +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      + + + + + Operation cannot be performed ! +

      +

      + Unexpected error occurred. Please Try again later. +

      + +
      + Ok +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      + + + + + Operation queued successfully ! +

      +

      + Operation has been queued successfully to be sent to the device. +

      + +
      + Ok +
      +
      +
      +
      +
      + +
      +
      +
      +
      +

      + + + + + Message sent successfully ! +

      +

      + Message has been queued to be sent to the device. +

      + +
      + Ok +
      +
      +
      +
      +
      +{{#each features}} + + + {{name}} + +
      +
      +
      +
      +

      + + + + + {{name}} +
      +

      +

      + {{#equal code "WIPE_DATA"}} + {{#equal type "android"}} + Enter PIN code (Optional - This is required only if the device type + is BYOD). +

      + +
      + +
      +
      + {{/equal}} + {{/equal}} + {{#equal code "NOTIFICATION"}} + Type your message below. +

      + + +
      + +
      +
      + {{/equal}} + {{#equal code "CHANGE_LOCK_CODE"}} + Type new lock-code below. +

      + +
      + {{/equal}} + Do you want to perform this operation on selected device(s) ? +
      +

      +
      + Yes + No +
      +
      +
      +
      +
      +{{/each}} +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.hbs new file mode 100644 index 000000000..d193515b4 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.hbs @@ -0,0 +1,3 @@ +{{#zone "bottomJs"}} + {{js "js/operation-mod.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.json new file mode 100644 index 000000000..62346cb87 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/operation-mod.json @@ -0,0 +1,4 @@ +{ + "version": "1.0.0", + "extends": "cdmf.unit.device.operation-mod" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js new file mode 100644 index 000000000..b35faac5a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-mod/public/js/operation-mod.js @@ -0,0 +1,1228 @@ +/* + * 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. + */ + +var operationModule = function () { + var publicMethods = {}; + var privateMethods = {}; + + // Constants to define platform types available + var platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" + }; + + // Constants to define operation types available + var operationTypeConstants = { + "PROFILE": "profile", + "CONFIG": "config", + "COMMAND": "command" + }; + + // Constants to define Android Operation Constants + var androidOperationConstants = { + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE", + "WIFI_OPERATION_CODE": "WIFI", + "WIPE_OPERATION_CODE": "WIPE_DATA", + "NOTIFICATION_OPERATION_CODE": "NOTIFICATION", + "CHANGE_LOCK_CODE_OPERATION_CODE": "CHANGE_LOCK_CODE" + }; + + // Constants to define Windows Operation Constants + var windowsOperationConstants = { + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE", + "NOTIFICATION_OPERATION_CODE": "NOTIFICATION", + "CHANGE_LOCK_CODE_OPERATION_CODE": "CHANGE_LOCK_CODE" + }; + + // Constants to define iOS Operation Constants + var iosOperationConstants = { + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "RESTRICTIONS_OPERATION_CODE": "RESTRICTION", + "WIFI_OPERATION_CODE": "WIFI", + "EMAIL_OPERATION_CODE": "EMAIL", + "AIRPLAY_OPERATION_CODE": "AIR_PLAY", + "LDAP_OPERATION_CODE": "LDAP", + "CALENDAR_OPERATION_CODE": "CALDAV", + "NOTIFICATION_OPERATION_CODE": "NOTIFICATION", + "CALENDAR_SUBSCRIPTION_OPERATION_CODE": "CALENDAR_SUBSCRIPTION", + "APN_OPERATION_CODE": "APN", + "CELLULAR_OPERATION_CODE": "CELLULAR" + }; + + publicMethods.getIOSServiceEndpoint = function (operationCode) { + var featureMap = { + "DEVICE_LOCK": "lock", + "ALARM": "alarm", + "LOCATION": "location", + "NOTIFICATION": "notification", + "AIR_PLAY": "airplay", + "RESTRICTION": "restriction", + "CELLULAR": "cellular", + "WIFI": "wifi", + "INSTALL_STORE_APPLICATION": "storeapplication", + "INSTALL_ENTERPRISE_APPLICATION": "enterpriseapplication", + "REMOVE_APPLICATION": "removeapplication", + "ENTERPRISE_WIPE": "enterprisewipe" + }; + return "/ios/operation/" + featureMap[operationCode]; + }; + + /** + * Convert the ios platform specific code to the generic payload. + * TODO: think of the possibility to follow a pattern to the key name (namespace?) + * @param operationCode + * @param operationPayload + * @returns {{}} + */ + privateMethods.generateGenericPayloadFromIOSPayload = function (operationCode, operationPayload) { + var payload = {}; + operationPayload = JSON.parse(operationPayload); + switch (operationCode) { + case iosOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]: + payload = { + "passcodePolicyForcePIN": operationPayload["forcePIN"], + "passcodePolicyAllowSimple": operationPayload["allowSimple"], + "passcodePolicyRequireAlphanumeric": operationPayload["requireAlphanumeric"], + "passcodePolicyMinLength": operationPayload["minLength"], + "passcodePolicyMinComplexChars": operationPayload["minComplexChars"], + "passcodePolicyMaxPasscodeAgeInDays": operationPayload["maxPINAgeInDays"], + "passcodePolicyPasscodeHistory": operationPayload["pinHistory"], + "passcodePolicyMaxAutoLock": operationPayload["maxInactivity"], + "passcodePolicyGracePeriod": operationPayload["maxGracePeriod"], + "passcodePolicyMaxFailedAttempts": operationPayload["maxFailedAttempts"] + }; + break; + case iosOperationConstants["RESTRICTIONS_OPERATION_CODE"]: + payload = { + "restrictionsAllowAccountModification": operationPayload["allowAccountModification"], + "restrictionsAllowAddingGameCenterFriends": operationPayload["allowAddingGameCenterFriends"], + "restrictionsAllowAirDrop": operationPayload["allowAirDrop"], + "restrictionsAllowAppCellularDataModification": operationPayload["allowAppCellularDataModification"], + "restrictionsAllowAppInstallation": operationPayload["allowAppInstallation"], + "restrictionsAllowAppRemoval": operationPayload["allowAppRemoval"], + "restrictionsAllowAssistant": operationPayload["allowAssistant"], + "restrictionsAllowAssistantUserGeneratedContent": operationPayload["allowAssistantUserGeneratedContent"], + "restrictionsAllowAssistantWhileLocked": operationPayload["allowAssistantWhileLocked"], + "restrictionsAllowBookstore": operationPayload["allowBookstore"], + "restrictionsAllowBookstoreErotica": operationPayload["allowBookstoreErotica"], + "restrictionsAllowCamera": operationPayload["allowCamera"], + "restrictionsAllowChat": operationPayload["allowChat"], + "restrictionsAllowCloudBackup": operationPayload["allowCloudBackup"], + "restrictionsAllowCloudDocumentSync": operationPayload["allowCloudDocumentSync"], + "restrictionsAllowCloudKeychainSync": operationPayload["allowCloudKeychainSync"], + "restrictionsAllowDiagnosticSubmission": operationPayload["allowDiagnosticSubmission"], + "restrictionsAllowExplicitContent": operationPayload["allowExplicitContent"], + "restrictionsAllowFindMyFriendsModification": operationPayload["allowFindMyFriendsModification"], + "restrictionsAllowFingerprintForUnlock": operationPayload["allowFingerprintForUnlock"], + "restrictionsAllowGameCenter": operationPayload["allowGameCenter"], + "restrictionsAllowGlobalBackgroundFetchWhenRoaming": operationPayload["allowGlobalBackgroundFetchWhenRoaming"], + "restrictionsAllowInAppPurchases": operationPayload["allowInAppPurchases"], + "restrictionsAllowLockScreenControlCenter": operationPayload["allowLockScreenControlCenter"], + "restrictionsAllowHostPairing": operationPayload["allowHostPairing"], + "restrictionsAllowLockScreenNotificationsView": operationPayload["allowLockScreenNotificationsView"], + "restrictionsAllowLockScreenTodayView": operationPayload["allowLockScreenTodayView"], + "restrictionsAllowMultiplayerGaming": operationPayload["allowMultiplayerGaming"], + "restrictionsAllowOpenFromManagedToUnmanaged": operationPayload["allowOpenFromManagedToUnmanaged"], + "restrictionsAllowOpenFromUnmanagedToManaged": operationPayload["allowOpenFromUnmanagedToManaged"], + "restrictionsAllowOTAPKIUpdates": operationPayload["allowOTAPKIUpdates"], + "restrictionsAllowPassbookWhileLocked": operationPayload["allowPassbookWhileLocked"], + "restrictionsAllowPhotoStream": operationPayload["allowPhotoStream"], + "restrictionsAllowSafari": operationPayload["allowSafari"], + "restrictionsSafariAllowAutoFill": operationPayload["safariAllowAutoFill"], + "restrictionsSafariForceFraudWarning": operationPayload["safariForceFraudWarning"], + "restrictionsSafariAllowJavaScript": operationPayload["safariAllowJavaScript"], + "restrictionsSafariAllowPopups": operationPayload["safariAllowPopups"], + "restrictionsAllowScreenShot": operationPayload["allowScreenShot"], + "restrictionsAllowSharedStream": operationPayload["allowSharedStream"], + "restrictionsAllowUIConfigurationProfileInstallation": operationPayload["allowUIConfigurationProfileInstallation"], + "restrictionsAllowUntrustedTLSPrompt": operationPayload["allowUntrustedTLSPrompt"], + "restrictionsAllowVideoConferencing": operationPayload["allowVideoConferencing"], + "restrictionsAllowVoiceDialing": operationPayload["allowVoiceDialing"], + "restrictionsAllowYouTube": operationPayload["allowYouTube"], + "restrictionsAllowITunes": operationPayload["allowiTunes"], + "restrictionsForceAssistantProfanityFilter": operationPayload["forceAssistantProfanityFilter"], + "restrictionsForceEncryptedBackup": operationPayload["forceEncryptedBackup"], + "restrictionsForceITunesStorePasswordEntry": operationPayload["forceITunesStorePasswordEntry"], + "restrictionsForceLimitAdTracking": operationPayload["forceLimitAdTracking"], + "restrictionsForceAirPlayOutgoingRequestsPairingPassword": operationPayload["forceAirPlayOutgoingRequestsPairingPassword"], + "restrictionsForceAirPlayIncomingRequestsPairingPassword": operationPayload["forceAirPlayIncomingRequestsPairingPassword"], + "restrictionsAllowManagedAppsCloudSync": operationPayload["allowManagedAppsCloudSync"], + "restrictionsAllowEraseContentAndSettings": operationPayload["allowEraseContentAndSettings"], + "restrictionsAllowSpotlightInternetResults": operationPayload["allowSpotlightInternetResults"], + "restrictionsAllowEnablingRestrictions": operationPayload["allowEnablingRestrictions"], + "restrictionsAllowActivityContinuation": operationPayload["allowActivityContinuation"], + "restrictionsAllowEnterpriseBookBackup": operationPayload["allowEnterpriseBookBackup"], + "restrictionsAllowEnterpriseBookMetadataSync": operationPayload["allowEnterpriseBookMetadataSync"], + "restrictionsAllowPodcasts": operationPayload["allowPodcasts"], + "restrictionsAllowDefinitionLookup": operationPayload["allowDefinitionLookup"], + "restrictionsAllowPredictiveKeyboard": operationPayload["allowPredictiveKeyboard"], + "restrictionsAllowAutoCorrection": operationPayload["allowAutoCorrection"], + "restrictionsAllowSpellCheck": operationPayload["allowSpellCheck"], + "restrictionsSafariAcceptCookies": operationPayload["safariAcceptCookies"], + "restrictionsAutonomousSingleAppModePermittedAppIDs": operationPayload["autonomousSingleAppModePermittedAppIDs"] + }; + break; + case iosOperationConstants["WIFI_OPERATION_CODE"]: + payload = { + "wifiHiddenNetwork": operationPayload["hiddenNetwork"], + "wifiSSID": operationPayload["ssid"], + "wifiAutoJoin": operationPayload["autoJoin"], + "wifiProxyType": operationPayload["proxyType"], + "wifiEncryptionType": operationPayload["encryptionType"], + "wifiIsHotSpot": operationPayload["hotspot"], + "wifiDomainName": operationPayload["domainName"], + "wifiServiceProviderRoamingEnabled": operationPayload["serviceProviderRoamingEnabled"], + "wifiDisplayedOperatorName": operationPayload["displayedOperatorName"], + "wifiRoamingConsortiumOIs": operationPayload["roamingConsortiumOIs"], + "wifiPassword": operationPayload["password"], + "wifiPayloadCertUUID": operationPayload["payloadCertificateUUID"], + "wifiProxyServer": operationPayload["proxyServer"], + "wifiProxyPort": operationPayload["proxyPort"], + "wifiProxyUsername": operationPayload["proxyUsername"], + "wifiProxyPassword": operationPayload["proxyPassword"], + "wifiProxyPACURL": operationPayload["proxyPACURL"], + "wifiProxyPACFallbackAllowed": operationPayload["proxyPACFallbackAllowed"], + "wifiNAIRealmNames": operationPayload["nairealmNames"], + "wifiMCCAndMNCs": operationPayload["mccandMNCs"], + "wifiEAPUsername": operationPayload.clientConfiguration["username"], + "wifiAcceptedEAPTypes": operationPayload.clientConfiguration["acceptEAPTypes"], + "wifiEAPPassword": operationPayload.clientConfiguration["userPassword"], + "wifiEAPOneTimePassword": operationPayload.clientConfiguration["oneTimePassword"], + "wifiPayloadCertificateAnchorUUIDs": operationPayload.clientConfiguration["payloadCertificateAnchorUUID"], + "wifiEAPOuterIdentity": operationPayload.clientConfiguration["outerIdentity"], + "wifiTLSTrustedServerNames": operationPayload.clientConfiguration["tlstrustedServerNames"], + "wifiEAPTLSAllowTrustExceptions": operationPayload.clientConfiguration["tlsallowTrustExceptions"], + "wifiEAPTLSCertIsRequired": operationPayload.clientConfiguration["tlscertificateIsRequired"], + "wifiEAPTLSInnerAuthType": operationPayload.clientConfiguration["ttlsinnerAuthentication"], + "wifiEAPFastUsePAC": operationPayload.clientConfiguration["eapfastusePAC"], + "wifiEAPFastProvisionPAC": operationPayload.clientConfiguration["eapfastprovisionPAC"], + "wifiEAPFastProvisionPACAnonymously": operationPayload.clientConfiguration["eapfastprovisionPACAnonymously"], + "wifiEAPSIMNoOfRands": operationPayload.clientConfiguration["eapsimnumberOfRANDs"] + }; + break; + case iosOperationConstants["EMAIL_OPERATION_CODE"]: + payload = { + "emailAccountDescription": operationPayload["emailAccountDescription"], + "emailAccountName": operationPayload["emailAccountName"], + "emailAccountType": operationPayload["emailAccountType"], + "emailAddress": operationPayload["emailAddress"], + "emailIncomingMailServerAuthentication": operationPayload["incomingMailServerAuthentication"], + "emailIncomingMailServerHostname": operationPayload["incomingMailServerHostName"], + "emailIncomingMailServerPort": operationPayload["incomingMailServerPortNumber"], + "emailIncomingUseSSL": operationPayload["incomingMailServerUseSSL"], + "emailIncomingMailServerUsername": operationPayload["incomingMailServerUsername"], + "emailIncomingMailServerPassword": operationPayload["incomingPassword"], + "emailOutgoingMailServerPassword": operationPayload["outgoingPassword"], + "emailOutgoingPasswordSameAsIncomingPassword": operationPayload["outgoingPasswordSameAsIncomingPassword"], + "emailOutgoingMailServerAuthentication": operationPayload["outgoingMailServerAuthentication"], + "emailOutgoingMailServerHostname": operationPayload["outgoingMailServerHostName"], + "emailOutgoingMailServerPort": operationPayload["outgoingMailServerPortNumber"], + "emailOutgoingUseSSL": operationPayload["outgoingMailServerUseSSL"], + "emailOutgoingMailServerUsername": operationPayload["outgoingMailServerUsername"], + "emailPreventMove": operationPayload["preventMove"], + "emailPreventAppSheet": operationPayload["preventAppSheet"], + "emailDisableMailRecentSyncing": operationPayload["disableMailRecentSyncing"], + "emailIncomingMailServerIMAPPathPrefix": operationPayload["incomingMailServerIMAPPathPrefix"], + "emailSMIMEEnabled": operationPayload["smimeenabled"], + "emailSMIMESigningCertificateUUID": operationPayload["smimesigningCertificateUUID"], + "emailSMIMEEncryptionCertificateUUID": operationPayload["smimeencryptionCertificateUUID"], + "emailSMIMEEnablePerMessageSwitch": operationPayload["smimeenablePerMessageSwitch"] + }; + break; + case iosOperationConstants["AIRPLAY_OPERATION_CODE"]: + payload = { + "airplayDestinations": operationPayload["airPlayDestinations"], + "airplayCredentials": operationPayload["airPlayCredentials"] + }; + break; + case iosOperationConstants["LDAP_OPERATION_CODE"]: + payload = { + "ldapAccountDescription": operationPayload["accountDescription"], + "ldapAccountHostname": operationPayload["accountHostName"], + "ldapUseSSL": operationPayload["accountUseSSL"], + "ldapAccountUsername": operationPayload["accountUsername"], + "ldapAccountPassword": operationPayload["accountPassword"], + "ldapSearchSettings": operationPayload["ldapSearchSettings"] + }; + break; + case iosOperationConstants["CALENDAR_OPERATION_CODE"]: + payload = { + "calendarAccountDescription": operationPayload["accountDescription"], + "calendarAccountHostname": operationPayload["hostName"], + "calendarAccountUsername": operationPayload["username"], + "calendarAccountPassword": operationPayload["password"], + "calendarUseSSL": operationPayload["useSSL"], + "calendarAccountPort": operationPayload["port"], + "calendarPrincipalURL": operationPayload["principalURL"] + }; + break; + case iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION_CODE"]: + payload = { + "calendarSubscriptionDescription": operationPayload["accountDescription"], + "calendarSubscriptionHostname": operationPayload["hostName"], + "calendarSubscriptionUsername": operationPayload["username"], + "calendarSubscriptionPassword": operationPayload["password"], + "calendarSubscriptionUseSSL": operationPayload["useSSL"] + }; + break; + case iosOperationConstants["APN_OPERATION_CODE"]: + payload = { + "apnConfigurations": operationPayload["apnConfigurations"] + }; + break; + case iosOperationConstants["CELLULAR_OPERATION_CODE"]: + payload = { + "cellularAttachAPNName": operationPayload["attachAPNName"], + "cellularAuthenticationType": operationPayload["authenticationType"], + "cellularUsername": operationPayload["username"], + "cellularPassword": operationPayload["password"], + "cellularAPNConfigurations": operationPayload["apnConfigurations"] + }; + break; + } + return payload; + }; + + privateMethods.generateIOSOperationPayload = function (operationCode, operationData, deviceList) { + var payload; + var operationType; + switch (operationCode) { + case iosOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "forcePIN": operationData["passcodePolicyForcePIN"], + "allowSimple": operationData["passcodePolicyAllowSimple"], + "requireAlphanumeric": operationData["passcodePolicyRequireAlphanumeric"], + "minLength": operationData["passcodePolicyMinLength"], + "minComplexChars": operationData["passcodePolicyMinComplexChars"], + "maxPINAgeInDays": operationData["passcodePolicyMaxPasscodeAgeInDays"], + "pinHistory": operationData["passcodePolicyPasscodeHistory"], + "maxInactivity": operationData["passcodePolicyMaxAutoLock"], + "maxGracePeriod": operationData["passcodePolicyGracePeriod"], + "maxFailedAttempts": operationData["passcodePolicyMaxFailedAttempts"] + } + }; + break; + case iosOperationConstants["WIFI_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "ssid": operationData["wifiSSID"], + "hiddenNetwork": operationData["wifiHiddenNetwork"], + "autoJoin": operationData["wifiAutoJoin"], + "proxyType": operationData["wifiProxyType"], + "encryptionType": operationData["wifiEncryptionType"], + "hotspot": operationData["wifiIsHotSpot"], + "domainName": operationData["wifiDomainName"], + "serviceProviderRoamingEnabled": operationData["wifiServiceProviderRoamingEnabled"], + "displayedOperatorName": operationData["wifiDisplayedOperatorName"], + "roamingConsortiumOIs": operationData["wifiRoamingConsortiumOIs"], + "password": operationData["wifiPassword"], + "clientConfiguration": { + "username": operationData["wifiEAPUsername"], + "acceptEAPTypes": operationData["wifiAcceptedEAPTypes"], + "userPassword": operationData["wifiEAPPassword"], + "oneTimePassword": operationData["wifiEAPOneTimePassword"], + "payloadCertificateAnchorUUID": operationData["wifiPayloadCertificateAnchorUUIDs"], + "outerIdentity": operationData["wifiEAPOuterIdentity"], + "tlstrustedServerNames": operationData["wifiTLSTrustedServerNames"], + "tlsallowTrustExceptions": operationData["wifiEAPTLSAllowTrustExceptions"], + "tlscertificateIsRequired": operationData["wifiEAPTLSCertIsRequired"], + "ttlsinnerAuthentication": operationData["wifiEAPTLSInnerAuthType"], + "eapfastusePAC": operationData["wifiEAPFastUsePAC"], + "eapfastprovisionPAC": operationData["wifiEAPFastProvisionPAC"], + "eapfastprovisionPACAnonymously": operationData["wifiEAPFastProvisionPACAnonymously"], + "eapsimnumberOfRANDs": operationData["wifiEAPSIMNoOfRands"] + }, + "payloadCertificateUUID": operationData["wifiPayloadCertUUID"], + "proxyServer": operationData["wifiProxyServer"], + "proxyPort": operationData["wifiProxyPort"], + "proxyUsername": operationData["wifiProxyUsername"], + "proxyPassword": operationData["wifiProxyPassword"], + "proxyPACURL": operationData["wifiProxyPACURL"], + "proxyPACFallbackAllowed": operationData["wifiProxyPACFallbackAllowed"], + "nairealmNames": operationData["wifiNAIRealmNames"], + "mccandMNCs": operationData["wifiMCCAndMNCs"] + } + }; + break; + case iosOperationConstants["RESTRICTIONS_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "allowAccountModification": operationData["restrictionsAllowAccountModification"], + "allowAddingGameCenterFriends": operationData["restrictionsAllowAddingGameCenterFriends"], + "allowAirDrop": operationData["restrictionsAllowAirDrop"], + "allowAppCellularDataModification": operationData["restrictionsAllowAppCellularDataModification"], + "allowAppInstallation": operationData["restrictionsAllowAppInstallation"], + "allowAppRemoval": operationData["restrictionsAllowAppRemoval"], + "allowAssistant": operationData["restrictionsAllowAssistant"], + "allowAssistantUserGeneratedContent": operationData["restrictionsAllowAssistantUserGeneratedContent"], + "allowAssistantWhileLocked": operationData["restrictionsAllowAssistantWhileLocked"], + "allowBookstore": operationData["restrictionsAllowBookstore"], + "allowBookstoreErotica": operationData["restrictionsAllowBookstoreErotica"], + "allowCamera": operationData["restrictionsAllowCamera"], + "allowChat": operationData["restrictionsAllowChat"], + "allowCloudBackup": operationData["restrictionsAllowCloudBackup"], + "allowCloudDocumentSync": operationData["restrictionsAllowCloudDocumentSync"], + "allowCloudKeychainSync": operationData["restrictionsAllowCloudKeychainSync"], + "allowDiagnosticSubmission": operationData["restrictionsAllowDiagnosticSubmission"], + "allowExplicitContent": operationData["restrictionsAllowExplicitContent"], + "allowFindMyFriendsModification": operationData["restrictionsAllowFindMyFriendsModification"], + "allowFingerprintForUnlock": operationData["restrictionsAllowFingerprintForUnlock"], + "allowGameCenter": operationData["restrictionsAllowGameCenter"], + "allowGlobalBackgroundFetchWhenRoaming": operationData["restrictionsAllowGlobalBackgroundFetchWhenRoaming"], + "allowInAppPurchases": operationData["restrictionsAllowInAppPurchases"], + "allowLockScreenControlCenter": operationData["restrictionsAllowLockScreenControlCenter"], + "allowHostPairing": operationData["restrictionsAllowHostPairing"], + "allowLockScreenNotificationsView": operationData["restrictionsAllowLockScreenNotificationsView"], + "allowLockScreenTodayView": operationData["restrictionsAllowLockScreenTodayView"], + "allowMultiplayerGaming": operationData["restrictionsAllowMultiplayerGaming"], + "allowOpenFromManagedToUnmanaged": operationData["restrictionsAllowOpenFromManagedToUnmanaged"], + "allowOpenFromUnmanagedToManaged": operationData["restrictionsAllowOpenFromUnmanagedToManaged"], + "allowOTAPKIUpdates": operationData["restrictionsAllowOTAPKIUpdates"], + "allowPassbookWhileLocked": operationData["restrictionsAllowPassbookWhileLocked"], + "allowPhotoStream": operationData["restrictionsAllowPhotoStream"], + "allowSafari": operationData["restrictionsAllowSafari"], + "safariAllowAutoFill": operationData["restrictionsSafariAllowAutoFill"], + "safariForceFraudWarning": operationData["restrictionsSafariForceFraudWarning"], + "safariAllowJavaScript": operationData["restrictionsSafariAllowJavaScript"], + "safariAllowPopups": operationData["restrictionsSafariAllowPopups"], + "allowScreenShot": operationData["restrictionsAllowScreenShot"], + "allowSharedStream": operationData["restrictionsAllowSharedStream"], + "allowUIConfigurationProfileInstallation": operationData["restrictionsAllowUIConfigurationProfileInstallation"], + "allowUntrustedTLSPrompt": operationData["restrictionsAllowUntrustedTLSPrompt"], + "allowVideoConferencing": operationData["restrictionsAllowVideoConferencing"], + "allowVoiceDialing": operationData["restrictionsAllowVoiceDialing"], + "allowYouTube": operationData["restrictionsAllowYouTube"], + "allowiTunes": operationData["restrictionsAllowITunes"], + "forceAssistantProfanityFilter": operationData["restrictionsForceAssistantProfanityFilter"], + "forceEncryptedBackup": operationData["restrictionsForceEncryptedBackup"], + "forceITunesStorePasswordEntry": operationData["restrictionsForceITunesStorePasswordEntry"], + "forceLimitAdTracking": operationData["restrictionsForceLimitAdTracking"], + "forceAirPlayOutgoingRequestsPairingPassword": operationData["restrictionsForceAirPlayOutgoingRequestsPairingPassword"], + "forceAirPlayIncomingRequestsPairingPassword": operationData["restrictionsForceAirPlayIncomingRequestsPairingPassword"], + "allowManagedAppsCloudSync": operationData["restrictionsAllowManagedAppsCloudSync"], + "allowEraseContentAndSettings": operationData["restrictionsAllowEraseContentAndSettings"], + "allowSpotlightInternetResults": operationData["restrictionsAllowSpotlightInternetResults"], + "allowEnablingRestrictions": operationData["restrictionsAllowEnablingRestrictions"], + "allowActivityContinuation": operationData["restrictionsAllowActivityContinuation"], + "allowEnterpriseBookBackup": operationData["restrictionsAllowEnterpriseBookBackup"], + "allowEnterpriseBookMetadataSync": operationData["restrictionsAllowEnterpriseBookMetadataSync"], + "allowPodcasts": operationData["restrictionsAllowPodcasts"], + "allowDefinitionLookup": operationData["restrictionsAllowDefinitionLookup"], + "allowPredictiveKeyboard": operationData["restrictionsAllowPredictiveKeyboard"], + "allowAutoCorrection": operationData["restrictionsAllowAutoCorrection"], + "allowSpellCheck": operationData["restrictionsAllowSpellCheck"], + "safariAcceptCookies": operationData["restrictionsSafariAcceptCookies"], + "autonomousSingleAppModePermittedAppIDs": operationData["restrictionsAutonomousSingleAppModePermittedAppIDs"] + } + }; + break; + case iosOperationConstants["EMAIL_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "emailAccountDescription": operationData["emailAccountDescription"], + "emailAccountName": operationData["emailAccountName"], + "emailAccountType": operationData["emailAccountType"], + "emailAddress": operationData["emailAddress"], + "incomingMailServerAuthentication": operationData["emailIncomingMailServerAuthentication"], + "incomingMailServerHostName": operationData["emailIncomingMailServerHostname"], + "incomingMailServerPortNumber": operationData["emailIncomingMailServerPort"], + "incomingMailServerUseSSL": operationData["emailIncomingUseSSL"], + "incomingMailServerUsername": operationData["emailIncomingMailServerUsername"], + "incomingPassword": operationData["emailIncomingMailServerPassword"], + "outgoingPassword": operationData["emailOutgoingMailServerPassword"], + "outgoingPasswordSameAsIncomingPassword": operationData["emailOutgoingPasswordSameAsIncomingPassword"], + "outgoingMailServerAuthentication": operationData["emailOutgoingMailServerAuthentication"], + "outgoingMailServerHostName": operationData["emailOutgoingMailServerHostname"], + "outgoingMailServerPortNumber": operationData["emailOutgoingMailServerPort"], + "outgoingMailServerUseSSL": operationData["emailOutgoingUseSSL"], + "outgoingMailServerUsername": operationData["emailOutgoingMailServerUsername"], + "preventMove": operationData["emailPreventMove"], + "preventAppSheet": operationData["emailPreventAppSheet"], + "disableMailRecentSyncing": operationData["emailDisableMailRecentSyncing"], + "incomingMailServerIMAPPathPrefix": operationData["emailIncomingMailServerIMAPPathPrefix"], + "smimeenabled": operationData["emailSMIMEEnabled"], + "smimesigningCertificateUUID": operationData["emailSMIMESigningCertificateUUID"], + "smimeencryptionCertificateUUID": operationData["emailSMIMEEncryptionCertificateUUID"], + "smimeenablePerMessageSwitch": operationData["emailSMIMEEnablePerMessageSwitch"] + } + }; + break; + case iosOperationConstants["AIRPLAY_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "airPlayDestinations": operationData["airplayDestinations"], + "airPlayCredentials": operationData["airplayCredentials"] + } + }; + break; + case iosOperationConstants["LDAP_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "accountDescription": operationData["ldapAccountDescription"], + "accountHostName": operationData["ldapAccountHostname"], + "accountUseSSL": operationData["ldapUseSSL"], + "accountUsername": operationData["ldapAccountUsername"], + "accountPassword": operationData["ldapAccountPassword"], + "ldapSearchSettings": operationData["ldapSearchSettings"] + } + }; + break; + case iosOperationConstants["CALENDAR_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "accountDescription": operationData["calendarAccountDescription"], + "hostName": operationData["calendarAccountHostname"], + "username": operationData["calendarAccountUsername"], + "password": operationData["calendarAccountPassword"], + "useSSL": operationData["calendarUseSSL"], + "port": operationData["calendarAccountPort"], + "principalURL": operationData["calendarPrincipalURL"] + } + }; + break; + case iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "accountDescription": operationData["calendarSubscriptionDescription"], + "hostName": operationData["calendarSubscriptionHostname"], + "username": operationData["calendarSubscriptionUsername"], + "password": operationData["calendarSubscriptionPassword"], + "useSSL": operationData["calendarSubscriptionUseSSL"] + } + }; + break; + case iosOperationConstants["APN_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "apnConfigurations": operationData["apnConfigurations"] + } + }; + break; + case iosOperationConstants["CELLULAR_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "attachAPNName": operationData["cellularAttachAPNName"], + "authenticationType": operationData["cellularAuthenticationType"], + "username": operationData["cellularUsername"], + "password": operationData["cellularPassword"], + "apnConfigurations": operationData["cellularAPNConfigurations"] + } + }; + break; + case iosOperationConstants["NOTIFICATION_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "message": operationData["message"] + } + }; + break; + default: + // If the operation is neither of above, it is a command operation + operationType = operationTypeConstants["COMMAND"]; + // Operation payload of a command operation is simply an array of device IDs + payload = deviceList; + } + + if (operationType == operationTypeConstants["PROFILE"] && deviceList) { + payload["deviceIDs"] = deviceList; + } + return payload; + }; + + /** + * Convert the android platform specific code to the generic payload. + * TODO: think of the possibility to follow a pattern to the key name (namespace?) + * @param operationCode + * @param operationPayload + * @returns {{}} + */ + privateMethods.generateGenericPayloadFromAndroidPayload = function (operationCode, operationPayload) { + var payload = {}; + operationPayload = JSON.parse(operationPayload); + switch (operationCode) { + case androidOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]: + payload = { + "passcodePolicyAllowSimple": operationPayload["allowSimple"], + "passcodePolicyRequireAlphanumeric": operationPayload["requireAlphanumeric"], + "passcodePolicyMinLength": operationPayload["minLength"], + "passcodePolicyMinComplexChars": operationPayload["minComplexChars"], + "passcodePolicyMaxPasscodeAgeInDays": operationPayload["maxPINAgeInDays"], + "passcodePolicyPasscodeHistory": operationPayload["pinHistory"], + "passcodePolicyMaxFailedAttempts": operationPayload["maxFailedAttempts"] + }; + break; + case androidOperationConstants["CAMERA_OPERATION_CODE"]: + payload = { + "cameraEnabled": operationPayload["enabled"] + }; + break; + case androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"]: + payload = { + "encryptStorageEnabled": operationPayload["encrypted"] + }; + break; + case androidOperationConstants["WIFI_OPERATION_CODE"]: + payload = { + "wifiSSID": operationPayload["ssid"], + "wifiPassword": operationPayload["password"] + }; + break; + } + return payload; + }; + + privateMethods.generateAndroidOperationPayload = function (operationCode, operationData, deviceList) { + var payload; + var operationType; + switch (operationCode) { + case androidOperationConstants["CAMERA_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "enabled": operationData["cameraEnabled"] + } + }; + break; + case androidOperationConstants["CHANGE_LOCK_CODE_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "lockCode": operationData["lockCode"] + } + }; + break; + case androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "encrypted": operationData["encryptStorageEnabled"] + } + }; + break; + case androidOperationConstants["NOTIFICATION_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "message": operationData["message"] + } + }; + break; + case androidOperationConstants["WIPE_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "pin": operationData["pin"] + } + }; + break; + case androidOperationConstants["WIFI_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "ssid": operationData["wifiSSID"], + "password": operationData["wifiPassword"] + } + }; + break; + case androidOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "allowSimple": operationData["passcodePolicyAllowSimple"], + "requireAlphanumeric": operationData["passcodePolicyRequireAlphanumeric"], + "minLength": operationData["passcodePolicyMinLength"], + "minComplexChars": operationData["passcodePolicyMinComplexChars"], + "maxPINAgeInDays": operationData["passcodePolicyMaxPasscodeAgeInDays"], + "pinHistory": operationData["passcodePolicyPasscodeHistory"], + "maxFailedAttempts": operationData["passcodePolicyMaxFailedAttempts"] + } + }; + break; + default: + // If the operation is neither of above, it is a command operation + operationType = operationTypeConstants["COMMAND"]; + // Operation payload of a command operation is simply an array of device IDs + payload = deviceList; + } + + if (operationType == operationTypeConstants["PROFILE"] && deviceList) { + payload["deviceIDs"] = deviceList; + } + + return payload; + }; + + publicMethods.getAndroidServiceEndpoint = function (operationCode) { + var featureMap = { + "WIFI": "wifi", + "CAMERA": "camera", + "DEVICE_LOCK": "lock", + "DEVICE_LOCATION": "location", + "CLEAR_PASSWORD": "clear-password", + "APPLICATION_LIST": "get-application-list", + "DEVICE_RING": "ring-device", + "DEVICE_REBOOT": "reboot-device", + "UPGRADE_FIRMWARE": "upgrade-firmware", + "DEVICE_MUTE": "mute", + "NOTIFICATION": "notification", + "ENCRYPT_STORAGE": "encrypt", + "CHANGE_LOCK_CODE": "change-lock-code", + "WEBCLIP": "webclip", + "INSTALL_APPLICATION": "install-application", + "UNINSTALL_APPLICATION": "uninstall-application", + "BLACKLIST_APPLICATIONS": "blacklist-applications", + "PASSCODE_POLICY": "password-policy", + "ENTERPRISE_WIPE": "enterprise-wipe", + "WIPE_DATA": "wipe-data" + }; + return "/mdm-android-agent/operation/" + featureMap[operationCode]; + }; + + /** + * Convert the windows platform specific code to the generic payload. + * TODO: think of the possibility to follow a pattern to the key name (namespace?) + * @param operationCode + * @param operationPayload + * @returns {{}} + */ + privateMethods.generateGenericPayloadFromWindowsPayload = function (operationCode, operationPayload) { + var payload = {}; + operationPayload = JSON.parse(operationPayload); + switch (operationCode) { + case windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]: + payload = { + "passcodePolicyAllowSimple": operationPayload["allowSimple"], + "passcodePolicyRequireAlphanumeric": operationPayload["requireAlphanumeric"], + "passcodePolicyMinLength": operationPayload["minLength"], + "passcodePolicyMinComplexChars": operationPayload["minComplexChars"], + "passcodePolicyMaxPasscodeAgeInDays": operationPayload["maxPINAgeInDays"], + "passcodePolicyPasscodeHistory": operationPayload["pinHistory"], + "passcodePolicyMaxFailedAttempts": operationPayload["maxFailedAttempts"] + }; + break; + case windowsOperationConstants["CAMERA_OPERATION_CODE"]: + payload = { + "cameraEnabled": operationPayload["enabled"] + }; + break; + case windowsOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"]: + payload = { + "encryptStorageEnabled": operationPayload["encrypted"] + }; + break; + } + return payload; + }; + + privateMethods.generateWindowsOperationPayload = function (operationCode, operationData, deviceList) { + var payload; + var operationType; + switch (operationCode) { + case windowsOperationConstants["CAMERA_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "enabled": operationData["cameraEnabled"] + } + }; + break; + case windowsOperationConstants["CHANGE_LOCK_CODE_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "lockCode": operationData["lockCode"] + } + }; + break; + case windowsOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "encrypted": operationData["encryptStorageEnabled"] + } + }; + break; + case windowsOperationConstants["NOTIFICATION_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "message": operationData["message"] + } + }; + break; + case windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]: + operationType = operationTypeConstants["PROFILE"]; + payload = { + "operation": { + "allowSimple": operationData["passcodePolicyAllowSimple"], + "requireAlphanumeric": operationData["passcodePolicyRequireAlphanumeric"], + "minLength": operationData["passcodePolicyMinLength"], + "minComplexChars": operationData["passcodePolicyMinComplexChars"], + "maxPINAgeInDays": operationData["passcodePolicyMaxPasscodeAgeInDays"], + "pinHistory": operationData["passcodePolicyPasscodeHistory"], + "maxFailedAttempts": operationData["passcodePolicyMaxFailedAttempts"] + } + }; + break; + default: + // If the operation is neither of above, it is a command operation + operationType = operationTypeConstants["COMMAND"]; + // Operation payload of a command operation is simply an array of device IDs + payload = deviceList; + } + + if (operationType == operationTypeConstants["PROFILE"] && deviceList) { + payload["deviceIDs"] = deviceList; + } + + return payload; + }; + + + publicMethods.getWindowsServiceEndpoint = function (operationCode) { + var featureMap = { + "CAMERA": "camera", + "DEVICE_LOCK": "lock", + "DEVICE_LOCATION": "location", + "CLEAR_PASSWORD": "clear-password", + "APPLICATION_LIST": "get-application-list", + "DEVICE_RING": "ring-device", + "DEVICE_REBOOT": "reboot-device", + "UPGRADE_FIRMWARE": "upgrade-firmware", + "DEVICE_MUTE": "mute", + "LOCK_RESET": "lock-reset", + "NOTIFICATION": "notification", + "ENCRYPT_STORAGE": "encrypt", + "CHANGE_LOCK_CODE": "change-lock-code", + "WEBCLIP": "webclip", + "INSTALL_APPLICATION": "install-application", + "UNINSTALL_APPLICATION": "uninstall-application", + "BLACKLIST_APPLICATIONS": "blacklist-applications", + "PASSCODE_POLICY": "password-policy", + "ENTERPRISE_WIPE": "enterprise-wipe", + "WIPE_DATA": "wipe-data", + "DISENROLL": "disenroll" + }; + return "/mdm-windows-agent/services/windows/operation/" + featureMap[operationCode]; + }; + /** + * Get the icon for the featureCode + * @param operationCode + * @returns icon class + */ + publicMethods.getAndroidIconForFeature = function (operationCode) { + var featureMap = { + "DEVICE_LOCK": "fw-lock", + "DEVICE_LOCATION": "fw-map-location", + "CLEAR_PASSWORD": "fw-key", + "ENTERPRISE_WIPE": "fw-clear", + "WIPE_DATA": "fw-database", + "DEVICE_RING": "fw-dial-up", + "DEVICE_REBOOT": "fw-refresh", + "UPGRADE_FIRMWARE": "fw-up-arrow", + "DEVICE_MUTE": "fw-incoming-call", + "NOTIFICATION": "fw-message", + "CHANGE_LOCK_CODE": "fw-security" + }; + return featureMap[operationCode]; + }; + + /** + * Get the icon for the featureCode + * @param operationCode + * @returns icon class + */ + publicMethods.getWindowsIconForFeature = function (operationCode) { + var featureMap = { + "DEVICE_LOCK": "fw-lock", + "DEVICE_LOCATION": "fw-map-location", + "DISENROLL": "fw-delete", + "WIPE_DATA": "fw-clear", + "DEVICE_RING": "fw-dial-up", + "DEVICE_REBOOT": "fw-refresh", + "UPGRADE_FIRMWARE": "fw-up-arrow", + "DEVICE_MUTE": "fw-incoming-call", + "NOTIFICATION": "fw-message", + "LOCK_RESET": "fw-key" + }; + return featureMap[operationCode]; + }; + + /** + * Get the icon for the featureCode + * @param operationCode + * @returns icon class + */ + publicMethods.getIOSIconForFeature = function (operationCode) { + var featureMap = { + "DEVICE_LOCK": "fw-lock", + "LOCATION": "fw-map-location", + "ENTERPRISE_WIPE": "fw-clear", + "NOTIFICATION": "fw-message", + "ALARM": "fw-dial-up" + }; + return featureMap[operationCode]; + }; + + /** + * Filter a list by a data attribute. + * @param prop + * @param val + * @returns {Array} + */ + $.fn.filterByData = function (prop, val) { + return this.filter( + function () { + return $(this).data(prop) == val; + } + ); + }; + + /** + * Method to generate Platform specific operation payload. + * + * @param platformType Platform Type of the profile + * @param operationCode Operation Codes to generate the profile from + * @param deviceList Optional device list to include in payload body for operations + * @returns {*} + */ + publicMethods.generatePayload = function (platformType, operationCode, deviceList) { + var payload; + var operationData = {}; + // capturing form input data designated by .operationDataKeys + $(".operation-data").filterByData("operation-code", operationCode).find(".operationDataKeys").each( + function () { + var operationDataObj = $(this); + var key = operationDataObj.data("key"); + var value; + if (operationDataObj.is(":text") || operationDataObj.is("textarea") || + operationDataObj.is(":password")) { + value = operationDataObj.val(); + } else if (operationDataObj.is(":checkbox")) { + value = operationDataObj.is(":checked"); + } else if (operationDataObj.is("select")) { + value = operationDataObj.find("option:selected").attr("value"); + } else if (operationDataObj.hasClass("grouped-array-input")) { + value = []; + var childInput; + var childInputValue; + if (operationDataObj.hasClass("one-column-input-array")) { + $(".child-input", this).each(function () { + childInput = $(this); + if (childInput.is(":text") || childInput.is("textarea") || childInput.is(":password")) { + childInputValue = childInput.val(); + } else if (childInput.is(":checkbox")) { + childInputValue = childInput.is(":checked"); + } else if (childInput.is("select")) { + childInputValue = childInput.find("option:selected").attr("value"); + } + // push to value + value.push(childInputValue); + }); + } else if (operationDataObj.hasClass("valued-check-box-array")) { + $(".child-input", this).each(function () { + childInput = $(this); + if (childInput.is(":checked")) { + // get associated value with check-box + childInputValue = childInput.data("value"); + // push to value + value.push(childInputValue); + } + }); + } else if (operationDataObj.hasClass("multi-column-joined-input-array")) { + var columnCount = operationDataObj.data("column-count"); + var inputCount = 0; + var joinedInput; + $(".child-input", this).each(function () { + childInput = $(this); + if (childInput.is(":text") || childInput.is("textarea") || childInput.is(":password")) { + childInputValue = childInput.val(); + } else if (childInput.is(":checkbox")) { + childInputValue = childInput.is(":checked"); + } else if (childInput.is("select")) { + childInputValue = childInput.find("option:selected").attr("value"); + } + inputCount++; + if (inputCount % columnCount == 1) { + // initialize joinedInput value + joinedInput = ""; + // append childInputValue to joinedInput + joinedInput += childInputValue; + } else if ((inputCount % columnCount) >= 2) { + // append childInputValue to joinedInput + joinedInput += childInputValue; + } else { + // append childInputValue to joinedInput + joinedInput += childInputValue; + // push to value + value.push(joinedInput); + } + }); + } else if (operationDataObj.hasClass("multi-column-key-value-pair-array")) { + columnCount = operationDataObj.data("column-count"); + inputCount = 0; + var childInputKey; + var keyValuePairJson; + $(".child-input", this).each(function () { + childInput = $(this); + childInputKey = childInput.data("child-key"); + if (childInput.is(":text") || childInput.is("textarea") || childInput.is(":password")) { + childInputValue = childInput.val(); + } else if (childInput.is(":checkbox")) { + childInputValue = childInput.is(":checked"); + } else if (childInput.is("select")) { + childInputValue = childInput.find("option:selected").attr("value"); + } + inputCount++; + if ((inputCount % columnCount) == 1) { + // initialize keyValuePairJson value + keyValuePairJson = {}; + // set key-value-pair + keyValuePairJson[childInputKey] = childInputValue; + } else if ((inputCount % columnCount) >= 2) { + // set key-value-pair + keyValuePairJson[childInputKey] = childInputValue; + } else { + // set key-value-pair + keyValuePairJson[childInputKey] = childInputValue; + // push to value + value.push(keyValuePairJson); + } + }); + } + } + operationData[key] = value; + } + ); + switch (platformType) { + case platformTypeConstants["ANDROID"]: + payload = privateMethods.generateAndroidOperationPayload(operationCode, operationData, deviceList); + break; + case platformTypeConstants["IOS"]: + payload = privateMethods.generateIOSOperationPayload(operationCode, operationData, deviceList); + break; + case platformTypeConstants["WINDOWS"]: + payload = privateMethods.generateWindowsOperationPayload(operationCode, operationData, deviceList); + break; + } + return payload; + }; + + /** + * Method to populate the Platform specific operation payload. + * + * @param platformType Platform Type of the profile + * @param operationCode Operation Codes to generate the profile from + * @param operationPayload payload + * @returns {*} + */ + publicMethods.populateUI = function (platformType, operationCode, operationPayload) { + var uiPayload; + switch (platformType) { + case platformTypeConstants["ANDROID"]: + uiPayload = privateMethods.generateGenericPayloadFromAndroidPayload(operationCode, operationPayload); + break; + case platformTypeConstants["IOS"]: + uiPayload = privateMethods.generateGenericPayloadFromIOSPayload(operationCode, operationPayload); + break; + case platformTypeConstants["WINDOWS"]: + uiPayload = privateMethods.generateGenericPayloadFromWindowsPayload(operationCode, operationPayload); + break; + } + // capturing form input data designated by .operationDataKeys + $(".operation-data").filterByData("operation-code", operationCode).find(".operationDataKeys").each( + function () { + var operationDataObj = $(this); + //TODO :remove + //operationDataObj.prop('disabled', true) + var key = operationDataObj.data("key"); + // retrieve corresponding input value associated with the key + var value = uiPayload[key]; + // populating input value according to the type of input + if (operationDataObj.is(":text") || + operationDataObj.is("textarea") || + operationDataObj.is(":password")) { + operationDataObj.val(value); + } else if (operationDataObj.is(":checkbox")) { + operationDataObj.prop("checked", value); + } else if (operationDataObj.is("select")) { + operationDataObj.val(value); + /* trigger a change of value, so that if slidable panes exist, + make them slide-down or slide-up accordingly */ + operationDataObj.trigger("change"); + } else if (operationDataObj.hasClass("grouped-array-input")) { + // then value is complex + var i, childInput; + var childInputIndex = 0; + // var childInputValue; + if (operationDataObj.hasClass("one-column-input-array")) { + // generating input fields to populate complex value + for (i = 0; i < value.length; ++i) { + operationDataObj.parent().find("a").filterByData("click-event", "add-form").click(); + } + // traversing through each child input + $(".child-input", this).each(function () { + childInput = $(this); + var childInputValue = value[childInputIndex]; + // populating extracted value in the UI according to the input type + if (childInput.is(":text") || + childInput.is("textarea") || + childInput.is(":password") || + childInput.is("select")) { + childInput.val(childInputValue); + } else if (childInput.is(":checkbox")) { + operationDataObj.prop("checked", childInputValue); + } + // incrementing childInputIndex + childInputIndex++; + }); + } else if (operationDataObj.hasClass("valued-check-box-array")) { + // traversing through each child input + $(".child-input", this).each(function () { + childInput = $(this); + // check if corresponding value of current checkbox exists in the array of values + if (value.indexOf(childInput.data("value")) != -1) { + // if YES, set checkbox as checked + childInput.prop("checked", true); + } + }); + } else if (operationDataObj.hasClass("multi-column-joined-input-array")) { + // generating input fields to populate complex value + for (i = 0; i < value.length; ++i) { + operationDataObj.parent().find("a").filterByData("click-event", "add-form").click(); + } + var columnCount = operationDataObj.data("column-count"); + var multiColumnJoinedInputArrayIndex = 0; + // handling scenarios specifically + if (operationDataObj.attr("id") == "wifi-mcc-and-mncs") { + // traversing through each child input + $(".child-input", this).each(function () { + childInput = $(this); + var multiColumnJoinedInput = value[multiColumnJoinedInputArrayIndex]; + var childInputValue; + if ((childInputIndex % columnCount) == 0) { + childInputValue = multiColumnJoinedInput.substring(3, 0) + } else { + childInputValue = multiColumnJoinedInput.substring(3); + // incrementing childInputIndex + multiColumnJoinedInputArrayIndex++; + } + // populating extracted value in the UI according to the input type + if (childInput.is(":text") || + childInput.is("textarea") || + childInput.is(":password") || + childInput.is("select")) { + childInput.val(childInputValue); + } else if (childInput.is(":checkbox")) { + operationDataObj.prop("checked", childInputValue); + } + // incrementing childInputIndex + childInputIndex++; + }); + } + } else if (operationDataObj.hasClass("multi-column-key-value-pair-array")) { + // generating input fields to populate complex value + for (i = 0; i < value.length; ++i) { + operationDataObj.parent().find("a").filterByData("click-event", "add-form").click(); + } + columnCount = operationDataObj.data("column-count"); + var multiColumnKeyValuePairArrayIndex = 0; + // traversing through each child input + $(".child-input", this).each(function () { + childInput = $(this); + var multiColumnKeyValuePair = value[multiColumnKeyValuePairArrayIndex]; + var childInputKey = childInput.data("child-key"); + var childInputValue = multiColumnKeyValuePair[childInputKey]; + // populating extracted value in the UI according to the input type + if (childInput.is(":text") || + childInput.is("textarea") || + childInput.is(":password") || + childInput.is("select")) { + childInput.val(childInputValue); + } else if (childInput.is(":checkbox")) { + operationDataObj.prop("checked", childInputValue); + } + // incrementing multiColumnKeyValuePairArrayIndex for the next row of inputs + if ((childInputIndex % columnCount) == (columnCount - 1)) { + multiColumnKeyValuePairArrayIndex++; + } + // incrementing childInputIndex + childInputIndex++; + }); + } + } + } + ); + }; + + /** + * generateProfile method is only used for policy-creation UIs. + * + * @param platformType Platform Type of the profile + * @param operationCodes Operation codes to generate the profile from + * @returns {{}} + */ + publicMethods.generateProfile = function (platformType, operationCodes) { + var generatedProfile = {}; + for (var i = 0; i < operationCodes.length; ++i) { + var operationCode = operationCodes[i]; + var payload = publicMethods.generatePayload(platformType, operationCode, null); + generatedProfile[operationCode] = payload["operation"]; + } + return generatedProfile; + }; + + /** + * populateProfile method is used to populate the html ui with saved payload. + * + * @param platformType Platform Type of the profile + * @param payload List of profileFeatures + * @returns [] configuredOperations array + */ + publicMethods.populateProfile = function (platformType, payload) { + var i, configuredOperations = []; + for (i = 0; i < payload.length; ++i) { + var configuredFeature = payload[i]; + var featureCode = configuredFeature["featureCode"]; + var operationPayload = configuredFeature["content"]; + //push the feature-code to the configuration array + configuredOperations.push(featureCode); + publicMethods.populateUI(platformType, featureCode, operationPayload); + } + return configuredOperations; + }; + + return publicMethods; +}(); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.hbs new file mode 100644 index 000000000..293177871 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.hbs @@ -0,0 +1,484 @@ +
      +
      + +
      +
      + General and Platform Specific Server Settings for the Tenant +
      +
      +
      +
      + + +
      + + + +
      +
      +
      + +

      + Policy Compliance Monitoring +
      +

      +
      + + +
      +
      + +
      +
      + + +
      +
      + + + +
      +
      +
      + +

      + Communication Protocol Configuration +
      +

      +
      + + +
      + +
      +
      + + +
      +
      + +
      +
      + + +
      + +
      + + +
      +
      +

      + End User License Agreement ( EULA ) +
      +

      + +
      + +
      +
      + +
      +
      +
      +
      + + + +
      +
      +
      + +

      + iOS SCEP Certificate Configurations +
      +

      + + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +

      + iOS Profile Configurations +
      +

      + + +
      + + +
      + +

      + iOS MDM Configurations +
      +

      + + +
      +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +

      + iOS APNS Configurations +
      +

      + + +
      +
      + + +
      + +
      + + +
      + +
      + + +
      + +

      + End User License Agreement (EULA) +
      +

      + +
      + +
      +
      + +
      +
      +
      +
      + + + +
      +
      +
      + +

      + Device Polling Configuration +
      +

      +
      +
      + + +
      +
      +

      + End User License Agreement ( EULA ) +
      +

      +
      + +
      +
      + +
      +
      +
      +
      + +
      +
      +
      +
      + + + +
      +
      +{{#zone "bottomJs"}} + {{js "js/platform-configuration.js"}} +{{/zone}} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.js new file mode 100644 index 000000000..354702f18 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.js @@ -0,0 +1,9 @@ +function onRequest(context) { + // var log = new Log("platform-configuration-unit backend js"); + var userModule = require("/app/modules/user.js")["userModule"]; + var typesListResponse = userModule.getPlatforms(); + if (typesListResponse["status"] == "success") { + context["types"] = typesListResponse["content"]; + } + return context; +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.json new file mode 100644 index 000000000..be0496bf6 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/configuration.json @@ -0,0 +1,4 @@ +{ + "version" : "1.0.0", + "extends": "cdmf.unit.platform.configuration" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/public/js/platform-configuration.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/public/js/platform-configuration.js new file mode 100644 index 000000000..7bbbad0b4 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.platform.configuration/public/js/platform-configuration.js @@ -0,0 +1,878 @@ +/* + * 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. + */ + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param inputString Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +function inputIsValid(regExp, inputString) { + return regExp.test(inputString); +} + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param inputString Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +function isPositiveInteger(str) { + return /^\+?(0|[1-9]\d*)$/.test(str); +} + +/** + * Get valid param. + * + * @param certificate + * @param cached param (in the registry) + * @returns {String} Returns the valid param + */ +function validateCertificateParams(param, cachedParam) { + if (param == '' && cachedParam != null) { + return cachedParam; + } else { + return param; + } +} + +/** + * Checks if an email address has the valid format or not. + * + * @param email Email address + * @returns {boolean} true if email has the valid format, otherwise false. + */ +function emailIsValid(email) { + var regExp = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; + return regExp.test(email); +} + +var iOSMDMCertificateName = null; +var iOSMDMCertificate = null; +var iOSAPNSCertificateName = null; +var iOSAPNSCertificate = null; + +var notifierTypeConstants = { + "LOCAL": "1", + "GCM": "2" +}; +// Constants to define platform types available +var platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" +}; + +var responseCodes = { + "CREATED": "Created", + "SUCCESS": "201", + "INTERNAL_SERVER_ERROR": "Internal Server Error" +}; + +var configParams = { + "NOTIFIER_TYPE": "notifierType", + "NOTIFIER_FREQUENCY": "notifierFrequency", + "GCM_API_KEY": "gcmAPIKey", + "GCM_SENDER_ID": "gcmSenderId", + "ANDROID_EULA": "androidEula", + "IOS_EULA": "iosEula", + "CONFIG_COUNTRY": "configCountry", + "CONFIG_STATE": "configState", + "CONFIG_LOCALITY": "configLocality", + "CONFIG_ORGANIZATION": "configOrganization", + "CONFIG_ORGANIZATION_UNIT": "configOrganizationUnit", + "MDM_CERT_PASSWORD": "MDMCertPassword", + "MDM_CERT_TOPIC_ID": "MDMCertTopicID", + "APNS_CERT_PASSWORD": "APNSCertPassword", + "MDM_CERT": "MDMCert", + "MDM_CERT_NAME": "MDMCertName", + "APNS_CERT": "APNSCert", + "APNS_CERT_NAME": "APNSCertName", + "ORG_DISPLAY_NAME": "organizationDisplayName", + "GENERAL_EMAIL_HOST": "emailHost", + "GENERAL_EMAIL_PORT": "emailPort", + "GENERAL_EMAIL_USERNAME": "emailUsername", + "GENERAL_EMAIL_PASSWORD": "emailPassword", + "GENERAL_EMAIL_SENDER_ADDRESS": "emailSender", + "GENERAL_EMAIL_TEMPLATE": "emailTemplate", + "COMMON_NAME": "commonName", + "KEYSTORE_PASSWORD": "keystorePassword", + "PRIVATE_KEY_PASSWORD": "privateKeyPassword", + "BEFORE_EXPIRE": "beforeExpire", + "AFTER_EXPIRE": "afterExpire", + "WINDOWS_EULA": "windowsLicense" +}; + +function promptErrorPolicyPlatform(errorMsg) { + var mainErrorMsgWrapper = "#platform-config-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(errorMsg); + $(mainErrorMsgWrapper).show(); +} + +$(document).ready(function () { + + var platformsSupported = $("#typeDiv").attr("typeData"); + $("#gcm-inputs").hide(); + tinymce.init({ + selector: "textarea", + height: 500, + theme: "modern", + plugins: [ + "autoresize", + "advlist autolink lists link image charmap print preview anchor", + "searchreplace visualblocks code fullscreen", + "insertdatetime image table contextmenu paste" + ], + toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" + }); + + var getAndroidConfigAPI = "/mdm-android-agent/configuration"; + var getGeneralConfigAPI = "/devicemgt_admin/configuration"; + var getIosConfigAPI = "/ios/configuration"; + var getWindowsConfigAPI = "/mdm-windows-agent/services/configuration"; + + /** + * Following requests would execute + * on page load event of platform configuration page in WSO2 EMM Console. + * Upon receiving the response, the parameters will be set to the fields, + * in case those configurations are already set. + */ + + if (platformsSupported.indexOf('android') != -1) { + invokerUtil.get( + getAndroidConfigAPI, + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if (config.name == configParams["NOTIFIER_TYPE"]) { + $("#android-config-notifier").val(config.value); + if (config.value != notifierTypeConstants["GCM"]) { + $("#gcm-inputs").hide(); + $("#local-inputs").show(); + } else { + $("#gcm-inputs").show(); + $("#local-inputs").hide(); + } + } else if (config.name == configParams["NOTIFIER_FREQUENCY"]) { + $("input#android-config-notifier-frequency").val(config.value / 1000); + } else if (config.name == configParams["GCM_API_KEY"]) { + $("input#android-config-gcm-api-key").val(config.value); + } else if (config.name == configParams["GCM_SENDER_ID"]) { + $("input#android-config-gcm-sender-id").val(config.value); + } else if (config.name == configParams["ANDROID_EULA"]) { + $("#android-eula").val(config.value); + } + } + } + }, function (data) { + console.log(data); + }); + } + + invokerUtil.get( + getGeneralConfigAPI, + function (data) { + data = JSON.parse(data); + if (data && data.configuration) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if (config.name == configParams["NOTIFIER_FREQUENCY"]) { + $("input#monitoring-config-frequency").val(config.value / 1000); + } + } + } + }, function (data) { + console.log(data); + }); + + if (platformsSupported.indexOf('windows') != -1) { + invokerUtil.get( + getWindowsConfigAPI, + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if (config.name == configParams["NOTIFIER_FREQUENCY"]) { + $("input#windows-config-notifier-frequency").val(config.value / 1000); + } else if (config.name == configParams["WINDOWS_EULA"]) { + $("#windows-eula").val(config.value); + } + } + } + }, function (data) { + console.log(data); + } + ); + } + + if (platformsSupported.indexOf('ios') != -1) { + invokerUtil.get( + getIosConfigAPI, + function (data) { + data = JSON.parse(data); + if (data != null && data.configuration != null) { + for (var i = 0; i < data.configuration.length; i++) { + var config = data.configuration[i]; + if (config.name == configParams["CONFIG_COUNTRY"]) { + $("input#ios-config-country").val(config.value); + } else if (config.name == configParams["CONFIG_STATE"]) { + $("input#ios-config-state").val(config.value); + } else if (config.name == configParams["CONFIG_LOCALITY"]) { + $("input#ios-config-locality").val(config.value); + } else if (config.name == configParams["CONFIG_ORGANIZATION"]) { + $("input#ios-config-organization").val(config.value); + } else if (config.name == configParams["CONFIG_ORGANIZATION_UNIT"]) { + $("input#ios-config-organization-unit").val(config.value); + } else if (config.name == configParams["MDM_CERT_PASSWORD"]) { + $("input#ios-config-mdm-certificate-password").val(config.value); + } else if (config.name == configParams["MDM_CERT_TOPIC_ID"]) { + $("input#ios-config-mdm-certificate-topic-id").val(config.value); + } else if (config.name == configParams["APNS_CERT_PASSWORD"]) { + $("input#ios-config-apns-certificate-password").val(config.value); + } else if (config.name == configParams["MDM_CERT_NAME"]) { + $("#mdm-cert-file-name").html(config.value); + iOSMDMCertificateName = config.value; + } else if (config.name == configParams["MDM_CERT"]) { + iOSMDMCertificate = config.value; + } else if (config.name == configParams["APNS_CERT_NAME"]) { + $("#apns-cert-file-name").html(config.value); + iOSAPNSCertificateName = config.value; + } else if (config.name == configParams["APNS_CERT"]) { + iOSAPNSCertificate = config.value; + } else if (config.name == configParams["ORG_DISPLAY_NAME"]) { + $("input#ios-org-display-name").val(config.value); + } else if (config.name == configParams["IOS_EULA"]) { + $("#ios-eula").val(config.value); + } + } + } + }, function (data) { + console.log(data); + } + ); + } + + $("select.select2[multiple=multiple]").select2({ + tags: true + }); + + $("#android-config-notifier").change(function () { + var notifierType = $("#android-config-notifier").find("option:selected").attr("value"); + if (notifierType != notifierTypeConstants["GCM"]) { + $("#gcm-inputs").hide(); + $("#local-inputs").show(); + } else { + $("#local-inputs").hide(); + $("#gcm-inputs").show(); + } + }); + + /** + * Following click function would execute + * when a user clicks on "Save" button + * on Android platform configuration page in WSO2 EMM Console. + */ + $("button#save-android-btn").click(function () { + var notifierType = $("#android-config-notifier").find("option:selected").attr("value"); + var notifierFrequency = $("input#android-config-notifier-frequency").val(); + var gcmAPIKey = $("input#android-config-gcm-api-key").val(); + var gcmSenderId = $("input#android-config-gcm-sender-id").val(); + var androidLicense = tinymce.get('android-eula').getContent(); + + var errorMsgWrapper = "#android-config-error-msg"; + var errorMsg = "#android-config-error-msg span"; + if (notifierType == notifierTypeConstants["LOCAL"] && !notifierFrequency) { + $(errorMsg).text("Notifier frequency is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (notifierType == notifierTypeConstants["LOCAL"] && !isPositiveInteger(notifierFrequency)) { + $(errorMsg).text("Provided notifier frequency is invalid. "); + $(errorMsgWrapper).removeClass("hidden"); + } else if (notifierType == notifierTypeConstants["GCM"] && !gcmAPIKey) { + $(errorMsg).text("GCM API Key is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (notifierType == notifierTypeConstants["GCM"] && !gcmSenderId) { + $(errorMsg).text("GCM Sender ID is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + + var addConfigFormData = {}; + var configList = new Array(); + + var type = { + "name": configParams["NOTIFIER_TYPE"], + "value": notifierType, + "contentType": "text" + }; + + var frequency = { + "name": configParams["NOTIFIER_FREQUENCY"], + "value": String(notifierFrequency * 1000), + "contentType": "text" + }; + + var gcmKey = { + "name": configParams["GCM_API_KEY"], + "value": gcmAPIKey, + "contentType": "text" + }; + + var gcmId = { + "name": configParams["GCM_SENDER_ID"], + "value": gcmSenderId, + "contentType": "text" + }; + + var androidEula = { + "name": configParams["ANDROID_EULA"], + "value": androidLicense, + "contentType": "text" + }; + + configList.push(type); + configList.push(frequency); + configList.push(androidEula); + if (notifierType == notifierTypeConstants["GCM"]) { + configList.push(gcmKey); + configList.push(gcmId); + } + + addConfigFormData.type = platformTypeConstants["ANDROID"]; + addConfigFormData.configuration = configList; + + var addConfigAPI = "/mdm-android-agent/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.responseCode == responseCodes["CREATED"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + $(errorMsg).text("An unexpected error occurred."); + $(errorMsgWrapper).removeClass("hidden"); + } + + + }, function (data) { + data = data.status; + if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + $(errorMsgWrapper).removeClass("hidden"); + } + ); + } + }); + + /** + * Following click function would execute + * when a user clicks on "Save" button + * on General platform configuration page in WSO2 EMM Console. + */ + $("button#save-general-btn").click(function () { + var notifierFrequency = $("input#monitoring-config-frequency").val(); + var errorMsgWrapper = "#email-config-error-msg"; + var errorMsg = "#email-config-error-msg span"; + + if (!notifierFrequency) { + $(errorMsg).text("Monitoring frequency is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!isPositiveInteger(notifierFrequency)) { + $(errorMsg).text("Provided monitoring frequency is invalid. "); + $(errorMsgWrapper).removeClass("hidden"); + } else { + var addConfigFormData = {}; + var configList = new Array(); + + var monitorFrequency = { + "name": configParams["NOTIFIER_FREQUENCY"], + "value": String((notifierFrequency * 1000)), + "contentType": "text" + }; + + configList.push(monitorFrequency); + addConfigFormData.configuration = configList; + + var addConfigAPI = "/devicemgt_admin/configuration"; + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.statusCode == responseCodes["SUCCESS"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function (data) { + data = data.status; + if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + $(errorMsgWrapper).removeClass("hidden"); + } + ); + } + }); + + var errorMsgWrapper = "#ios-config-error-msg"; + var errorMsg = "#ios-config-error-msg span"; + var fileTypes = ['pfx']; + var notSupportedError = false; + + var base64MDMCert = ""; + var fileInputMDMCert = $('#ios-config-mdm-certificate'); + var fileNameMDMCert = ""; + var invalidFormatMDMCert = false; + + var base64APNSCert = ""; + var fileInputAPNSCert = $('#ios-config-apns-certificate'); + var fileNameAPNSCert = ""; + var invalidFormatAPNSCert = false; + + $(fileInputMDMCert).change(function () { + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + notSupportedError = true; + return; + } + + var file = fileInputMDMCert[0].files[0]; + fileNameMDMCert = file.name; + var extension = file.name.split('.').pop().toLowerCase(), + isSuccess = fileTypes.indexOf(extension) > -1; + + if (isSuccess) { + var fileReader = new FileReader(); + fileReader.onload = function (event) { + base64MDMCert = event.target.result; + }; + fileReader.readAsDataURL(file); + invalidFormatMDMCert = false; + } else { + base64MDMCert = ""; + invalidFormatMDMCert = true; + } + }); + + $(fileInputAPNSCert).change(function () { + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + notSupportedError = true; + return; + } + + var file = fileInputAPNSCert[0].files[0]; + fileNameAPNSCert = file.name; + var extension = file.name.split('.').pop().toLowerCase(), + isSuccess = fileTypes.indexOf(extension) > -1; + + if (isSuccess) { + var fileReader = new FileReader(); + fileReader.onload = function (event) { + base64APNSCert = event.target.result; + }; + fileReader.readAsDataURL(file); + invalidFormatAPNSCert = false; + } else { + base64MDMCert = ""; + invalidFormatAPNSCert = true; + } + }); + + $("button#save-ios-btn").click(function () { + + var configCountry = $("#ios-config-country").val(); + var configState = $("#ios-config-state").val(); + var configLocality = $("#ios-config-locality").val(); + var configOrganization = $("#ios-config-organization").val(); + var configOrganizationUnit = $("#ios-config-organization-unit").val(); + var MDMCertPassword = $("#ios-config-mdm-certificate-password").val(); + var MDMCertTopicID = $("#ios-config-mdm-certificate-topic-id").val(); + var APNSCertPassword = $("#ios-config-apns-certificate-password").val(); + var configOrgDisplayName = $("#ios-org-display-name").val(); + var iosLicense = tinymce.get('ios-eula').getContent(); + + fileNameMDMCert = validateCertificateParams(fileNameMDMCert, iOSMDMCertificateName); + fileNameAPNSCert = validateCertificateParams(fileNameAPNSCert, iOSAPNSCertificateName); + base64MDMCert = validateCertificateParams(base64MDMCert, iOSMDMCertificate); + base64APNSCert = validateCertificateParams(base64APNSCert, iOSAPNSCertificate); + + if (!configCountry) { + $(errorMsg).text("SCEP country is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configState) { + $(errorMsg).text("SCEP state is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configLocality) { + $(errorMsg).text("SCEP locality is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configOrganization) { + $(errorMsg).text("SCEP organization is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configOrganizationUnit) { + $(errorMsg).text("SCEP organization unit is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!MDMCertPassword) { + $(errorMsg).text("MDM certificate password is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!MDMCertTopicID) { + $(errorMsg).text("MDM certificate topic ID is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!APNSCertPassword) { + $(errorMsg).text("APNS certificate password is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (notSupportedError) { + $(errorMsg).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (invalidFormatMDMCert) { + $(errorMsg).text("MDM certificate needs to be in pfx format."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (base64MDMCert == '') { + $(errorMsg).text("MDM certificate is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (invalidFormatAPNSCert) { + $(errorMsg).text("APNS certificate needs to be in pfx format."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (base64APNSCert == '') { + $(errorMsg).text("APNS certificate is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else if (!configOrgDisplayName) { + $(errorMsg).text("Organization display name is a required field. It cannot be empty."); + $(errorMsgWrapper).removeClass("hidden"); + } else { + var addConfigFormData = {}; + var configList = new Array(); + + var configCountry = { + "name": configParams["CONFIG_COUNTRY"], + "value": configCountry, + "contentType": "text" + }; + + var configState = { + "name": configParams["CONFIG_STATE"], + "value": configState, + "contentType": "text" + }; + + var configLocality = { + "name": configParams["CONFIG_LOCALITY"], + "value": configLocality, + "contentType": "text" + }; + + var configOrganization = { + "name": configParams["CONFIG_ORGANIZATION"], + "value": configOrganization, + "contentType": "text" + }; + + var configOrganizationUnit = { + "name": configParams["CONFIG_ORGANIZATION_UNIT"], + "value": configOrganizationUnit, + "contentType": "text" + }; + + var MDMCertPassword = { + "name": configParams["MDM_CERT_PASSWORD"], + "value": MDMCertPassword, + "contentType": "text" + }; + + var MDMCertTopicID = { + "name": configParams["MDM_CERT_TOPIC_ID"], + "value": MDMCertTopicID, + "contentType": "text" + }; + + var APNSCertPassword = { + "name": configParams["APNS_CERT_PASSWORD"], + "value": APNSCertPassword, + "contentType": "text" + }; + + var paramBase64MDMCert = { + "name": configParams["MDM_CERT"], + "value": base64MDMCert, + "contentType": "text" + }; + + var MDMCertName = { + "name": configParams["MDM_CERT_NAME"], + "value": fileNameMDMCert, + "contentType": "text" + }; + + var paramBase64APNSCert = { + "name": configParams["APNS_CERT"], + "value": base64APNSCert, + "contentType": "text" + }; + + var APNSCertName = { + "name": configParams["APNS_CERT_NAME"], + "value": fileNameAPNSCert, + "contentType": "text" + }; + + var paramOrganizationDisplayName = { + "name": configParams["ORG_DISPLAY_NAME"], + "value": configOrgDisplayName, + "contentType": "text" + }; + + var iosEula = { + "name": configParams["IOS_EULA"], + "value": iosLicense, + "contentType": "text" + }; + + configList.push(configCountry); + configList.push(configState); + configList.push(configLocality); + configList.push(configOrganization); + configList.push(configOrganizationUnit); + configList.push(MDMCertPassword); + configList.push(MDMCertTopicID); + configList.push(APNSCertPassword); + configList.push(paramBase64MDMCert); + configList.push(MDMCertName); + configList.push(paramBase64APNSCert); + configList.push(APNSCertName); + configList.push(paramOrganizationDisplayName); + configList.push(iosEula); + + addConfigFormData.type = platformTypeConstants["IOS"]; + addConfigFormData.configuration = configList; + + var addConfigAPI = "/ios/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.responseCode == responseCodes["CREATED"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 400) { + $(errorMsg).text("Configurations cannot be empty."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapper).removeClass("hidden"); + }, function (data) { + data = data.status; + if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + $(errorMsgWrapper).removeClass("hidden"); + } + ); + } + + }); + + var errorMsgWrapperWindows = "#windows-config-error-msg"; + var errorMsgWindows = "#windows-config-error-msg span"; + var fileTypesWindows = ['jks']; + var notSupportedError = false; + + var base64WindowsMDMCert = ""; + var fileInputWindowsMDMCert = $('#windows-config-mdm-certificate'); + var fileNameWindowsMDMCert = ""; + var invalidFormatWindowsMDMCert = false; + + $(fileInputWindowsMDMCert).change(function () { + + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + $(errorMsgWindows).text("The File APIs are not fully supported in this browser."); + $(errorMsgWrapperWindows).removeClass("hidden"); + notSupportedError = true; + return; + } + + var file = fileInputWindowsMDMCert[0].files[0]; + fileNameWindowsMDMCert = file.name; + var extension = file.name.split('.').pop().toLowerCase(), + isSuccess = fileTypesWindows.indexOf(extension) > -1; + + if (isSuccess) { + var fileReader = new FileReader(); + fileReader.onload = function (event) { + base64WindowsMDMCert = event.target.result; + }; + fileReader.readAsDataURL(file); + invalidFormatWindowsMDMCert = false; + } else { + base64MDMCert = ""; + invalidFormatWindowsMDMCert = true; + } + }); + + $("button#save-windows-btn").click(function () { + + var notifierFrequency = $("#windows-config-notifier-frequency").val(); + var windowsLicense = tinymce.get('windows-eula').getContent(); + + if (!notifierFrequency) { + $(errorMsgWindows).text("Polling Interval is a required field. It cannot be empty."); + $(errorMsgWrapperWindows).removeClass("hidden"); + } else if (!windowsLicense) { + $(errorMsgWindows).text("License is a required field. It cannot be empty."); + $(errorMsgWrapperWindows).removeClass("hidden"); + } else if (!$.isNumeric(notifierFrequency)) { + $(errorMsgWindows).text("Provided Notifier frequency is invalid. It must be a number."); + $(errorMsgWrapperWindows).removeClass("hidden"); + } else { + var addConfigFormData = {}; + var configList = new Array(); + + var paramNotifierFrequency = { + "name": configParams["NOTIFIER_FREQUENCY"], + "value": String(notifierFrequency * 1000), + "contentType": "text" + }; + + var windowsEula = { + "name": configParams["WINDOWS_EULA"], + "value": windowsLicense, + "contentType": "text" + }; + + configList.push(paramNotifierFrequency); + configList.push(windowsEula); + + addConfigFormData.type = platformTypeConstants["WINDOWS"]; + addConfigFormData.configuration = configList; + + var addConfigAPI = "/mdm-windows-agent/services/configuration"; + + invokerUtil.post( + addConfigAPI, + addConfigFormData, + function (data) { + data = JSON.parse(data); + if (data.responseCode == responseCodes["CREATED"]) { + $("#config-save-form").addClass("hidden"); + $("#record-created-msg").removeClass("hidden"); + } else if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 400) { + $(errorMsg).text("Configurations cannot be empty."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + + $(errorMsgWrapperWindows).removeClass("hidden"); + }, function (data) { + data = data.status; + if (data == 500) { + $(errorMsg).text("Exception occurred at backend."); + } else if (data == 403) { + $(errorMsg).text("Action was not permitted."); + } else { + $(errorMsg).text("An unexpected error occurred."); + } + $(errorMsgWrapper).removeClass("hidden"); + } + ); + } + + }); +}); + +// Start of HTML embedded invoke methods +var showAdvanceOperation = function (operation, button) { + $(button).addClass('selected'); + $(button).siblings().removeClass('selected'); + var enabledPlatforms = $("#supportedPlatforms"); + var isPluginEnabled = false; + switch (operation) { + case 'ios': + if (enabledPlatforms.data("ios")) { + isPluginEnabled = true; + } + break; + case 'windows': + if (enabledPlatforms.data("windows")) { + isPluginEnabled = true; + } + break; + case 'android': + if (enabledPlatforms.data("android")) { + isPluginEnabled = true; + } + break; + case 'general': + isPluginEnabled = true; + break; + } + if (isPluginEnabled) { + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="' + operation + '"]').show(); + $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide(); + } else { + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="error"]').show(); + $(hiddenOperation + '[data-operation="error"]').siblings().hide(); + promptErrorPolicyPlatform("To use " + operation + " related functionalities you need to configure the server " + + "accordingly.Please refer to the user guiled."); + } +}; diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.hbs new file mode 100644 index 000000000..4f85e36c7 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.hbs @@ -0,0 +1,223 @@ + +
      +
      + + + + + + + + + +
      +
      +

      EDIT POLICY

      +
      +
      +
      +
      +
      +

      Step 1: Edit current profile

      +
      + +
      +
      +
      + + Loading platform features . . . +
      +
      +
      +
      + +
      +
      +
      +
      + + + +
      +
      +{{#zone "bottomJs"}} + + + + {{js "js/policy-create.js"}} +{{/zone}} + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.js new file mode 100644 index 000000000..94f7423c1 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.js @@ -0,0 +1,26 @@ +/* + * 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("policy-view-edit-unit backend js"); + log.debug("calling policy-view-edit-unit"); + var userModule = require("/app/modules/user.js").userModule; + context.roles = userModule.getRoles().content; + context.users = userModule.getUsersByUsername().content; + return context; +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.json new file mode 100644 index 000000000..fd2590129 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/edit.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/js/policy-create.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/js/policy-create.js new file mode 100644 index 000000000..fafc43318 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/js/policy-create.js @@ -0,0 +1,2321 @@ +/* + * 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. + */ + +var validateStep = {}; +var skipStep = {}; +var stepForwardFrom = {}; +var stepBackFrom = {}; +var policy = {}; +var configuredOperations = []; +var currentlyEffected = {}; + +// Constants to define platform types available +var platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" +}; + +// Constants to define platform types ids. +var platformTypeIds = { + "ANDROID": 1, + "IOS": 3, + "WINDOWS": 2 +}; + +// Constants to define Android Operation Constants +var androidOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION": "camera", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION": "encrypt-storage", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE", + "WIFI_OPERATION": "wifi", + "WIFI_OPERATION_CODE": "WIFI" +}; + +// Constants to define Android Operation Constants +var windowsOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION": "camera", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION": "encrypt-storage", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE" +}; + +// Constants to define iOS Operation Constants +var iosOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "RESTRICTIONS_OPERATION": "restrictions", + "RESTRICTIONS_OPERATION_CODE": "RESTRICTION", + "WIFI_OPERATION": "wifi", + "WIFI_OPERATION_CODE": "WIFI", + "EMAIL_OPERATION": "email", + "EMAIL_OPERATION_CODE": "EMAIL", + "AIRPLAY_OPERATION": "airplay", + "AIRPLAY_OPERATION_CODE": "AIR_PLAY", + "LDAP_OPERATION": "ldap", + "LDAP_OPERATION_CODE": "LDAP", + "CALENDAR_OPERATION": "calendar", + "CALENDAR_OPERATION_CODE": "CALDAV", + "CALENDAR_SUBSCRIPTION_OPERATION": "calendar-subscription", + "CALENDAR_SUBSCRIPTION_OPERATION_CODE": "CALENDAR_SUBSCRIPTION", + "APN_OPERATION": "apn", + "APN_OPERATION_CODE": "APN", + "CELLULAR_OPERATION": "cellular", + "CELLULAR_OPERATION_CODE": "CELLULAR" +}; + +/** + * Method to update the visibility (i.e. disabled or enabled view) + * of grouped input according to the values + * that they currently possess. + * @param domElement HTML grouped-input element with class name "grouped-input" + */ +var updateGroupedInputVisibility = function (domElement) { + if ($(".parent-input:first", domElement).is(":checked")) { + if ($(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).removeClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', false); + }); + } else { + if (!$(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).addClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', true); + }); + } +}; + +skipStep["policy-platform"] = function (policyPayloadObj) { + policy["name"] = policyPayloadObj["policyName"]; + policy["platform"] = policyPayloadObj["profile"]["deviceType"]["name"]; + policy["platformId"] = policyPayloadObj["profile"]["deviceType"]["id"]; + var userRoleInput = $("#user-roles-input"); + var ownershipInput = $("#ownership-input"); + var userInput = $("#users-input"); + var actionInput = $("#action-input"); + var policyNameInput = $("#policy-name-input"); + var policyDescriptionInput = $("#policy-description-input"); + currentlyEffected["roles"] = policyPayloadObj.roles; + currentlyEffected["users"] = policyPayloadObj.users; + userRoleInput.val(currentlyEffected["roles"]).trigger("change"); + userInput.val(currentlyEffected["users"]).trigger("change"); + + if (currentlyEffected["users"].length > 0) { + $("#users-radio-btn").prop("checked", true) + $("#users-select-field").show(); + $("#user-roles-select-field").hide(); + } + ownershipInput.val(policyPayloadObj.ownershipType); + actionInput.val(policyPayloadObj.compliance); + policyNameInput.val(policyPayloadObj["policyName"]); + policyDescriptionInput.val(policyPayloadObj["description"]); + // updating next-page wizard title with selected platform + $("#policy-profile-page-wizard-title").text("EDIT " + policy["platform"] + " POLICY - " + policy["name"]); + + var deviceType = policy["platform"]; + var hiddenOperationsByDeviceType = $("#hidden-operations-" + deviceType); + var hiddenOperationsByDeviceTypeCacheKey = deviceType + "HiddenOperations"; + var hiddenOperationsByDeviceTypeSrc = hiddenOperationsByDeviceType.attr("src"); + + setTimeout( + function () { + $.template(hiddenOperationsByDeviceTypeCacheKey, hiddenOperationsByDeviceTypeSrc, function (template) { + var content = template(); + // pushing profile feature input elements + $(".wr-advance-operations").html(content); + // populating values and getting the list of configured features + var configuredOperations = operationModule. + populateProfile(policy["platform"], policyPayloadObj["profile"]["profileFeaturesList"]); + // updating grouped input visibility according to the populated values + $(".wr-advance-operations li.grouped-input").each(function () { + updateGroupedInputVisibility(this); + }); + // enabling previously configured options of last update + for (var i = 0; i < configuredOperations.length; ++i) { + var configuredOperation = configuredOperations[i]; + $(".operation-data").filterByData("operation-code", configuredOperation). + find(".panel-title .wr-input-control.switch input[type=checkbox]").each(function () { + $(this).click(); + }); + } + }); + }, + 250 // time delayed for the execution of above function, 250 milliseconds + ); +}; + +/** + * Checks if provided number is valid against a range. + * + * @param numberInput Number Input + * @param min Minimum Limit + * @param max Maximum Limit + * @returns {boolean} Returns true if input is within the specified range + */ +var inputIsValidAgainstRange = function (numberInput, min, max) { + return (numberInput == min || (numberInput > min && numberInput < max) || numberInput == max); +}; + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param input Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +var inputIsValidAgainstRegExp = function (regExp, input) { + return regExp.test(input); +}; + +validateStep["policy-profile"] = function () { + var validationStatusArray = []; + var validationStatus; + var operation; + + // starting validation process and updating validationStatus + if (policy["platform"] == platformTypeConstants["ANDROID"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(androidOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = androidOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + var continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + var passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + var passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CAMERA + if ($.inArray(androidOperationConstants["CAMERA_OPERATION_CODE"], configuredOperations) != -1) { + // if CAMERA is configured + operation = androidOperationConstants["CAMERA_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating ENCRYPT_STORAGE + if ($.inArray(androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"], configuredOperations) != -1) { + // if ENCRYPT_STORAGE is configured + operation = androidOperationConstants["ENCRYPT_STORAGE_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating WIFI + if ($.inArray(androidOperationConstants["WIFI_OPERATION_CODE"], configuredOperations) != -1) { + // if WIFI is configured + operation = androidOperationConstants["WIFI_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var wifiSSID = $("input#wifi-ssid").val(); + if (!wifiSSID) { + validationStatus = { + "error": true, + "subErrorMsg": "WIFI SSID is not given. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + } + } + if (policy["platform"] == platformTypeConstants["WINDOWS"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = windowsOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + var continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + var passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + var passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CAMERA + if ($.inArray(windowsOperationConstants["CAMERA_OPERATION_CODE"], configuredOperations) != -1) { + // if CAMERA is configured + operation = windowsOperationConstants["CAMERA_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating ENCRYPT_STORAGE + if ($.inArray(windowsOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"], configuredOperations) != -1) { + // if ENCRYPT_STORAGE is configured + operation = windowsOperationConstants["ENCRYPT_STORAGE_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + + } + } else if (policy["platform"] == platformTypeConstants["IOS"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(iosOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = iosOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating RESTRICTIONS + if ($.inArray(iosOperationConstants["RESTRICTIONS_OPERATION_CODE"], configuredOperations) != -1) { + // if RESTRICTION is configured + operation = iosOperationConstants["RESTRICTIONS_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // getting input values to be validated + var restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs = + "div#restrictions-autonomous-single-app-mode-permitted-app-ids .child-input"; + if ($(restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs).length > 0) { + var childInput; + var childInputArray = []; + var emptyChildInputCount = 0; + var duplicatesExist = false; + // looping through each child input + $(restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + var initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + var m, poppedChildInput; + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + var n; + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more permitted App ID entries in " + + "Autonomous Single App Mode are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with permitted App ID entries in " + + "Autonomous Single App Mode.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating WIFI + if ($.inArray(iosOperationConstants["WIFI_OPERATION_CODE"], configuredOperations) != -1) { + // if WIFI is configured + operation = iosOperationConstants["WIFI_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // getting input values to be validated + wifiSSID = $("input#wifi-ssid").val(); + var wifiDomainName = $("input#wifi-domain-name").val(); + if (!wifiSSID && !wifiDomainName) { + validationStatus = { + "error": true, + "subErrorMsg": "Both Wi-Fi SSID and Wi-Fi Domain Name are not given. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + // getting proxy-setup value + var wifiProxyType = $("select#wifi-proxy-type").find("option:selected").attr("value"); + if (wifiProxyType == "Manual") { + // adds up additional fields to be validated + var wifiProxyServer = $("input#wifi-proxy-server").val(); + if (!wifiProxyServer) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Server is required. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var wifiProxyPort = $("input#wifi-proxy-port").val(); + if (!wifiProxyPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port is required. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(wifiProxyPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(wifiProxyPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + } + + if (continueToCheckNextInputs) { + // getting encryption-type value + var wifiEncryptionType = $("select#wifi-encryption-type").find("option:selected").attr("value"); + if (wifiEncryptionType != "None") { + var wifiPayloadCertificateAnchorUUIDsGridChildInputs = + "div#wifi-payload-certificate-anchor-uuids .child-input"; + if ($(wifiPayloadCertificateAnchorUUIDsGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiPayloadCertificateAnchorUUIDsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Payload Certificate " + + "Anchor UUIDs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist " + + "with Payload Certificate Anchor UUIDs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var wifiTLSTrustedServerNamesGridChildInputs = + "div#wifi-tls-trusted-server-names .child-input"; + if ($(wifiTLSTrustedServerNamesGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiTLSTrustedServerNamesGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more TLS Trusted Server Names are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist " + + "with TLS Trusted Server Names.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + } + } + + if (continueToCheckNextInputs) { + var wifiRoamingConsortiumOIsGridChildInputs = "div#wifi-roaming-consortium-ois .child-input"; + if ($(wifiRoamingConsortiumOIsGridChildInputs).length > 0) { + emptyChildInputCount = 0; + var outOfAllowedLengthCount = 0; + var invalidAgainstRegExCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiRoamingConsortiumOIsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!inputIsValidAgainstLength(childInput, 6, 6) && !inputIsValidAgainstLength(childInput, 10, 10)) { + outOfAllowedLengthCount++; + } else if (!inputIsValidAgainstRegExp(/^[a-fA-F0-9]+$/, childInput)) { + invalidAgainstRegExCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (outOfAllowedLengthCount > 0) { + // if outOfMaxAllowedLength input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs " + + "are out of allowed length.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (invalidAgainstRegExCount > 0) { + // if invalid inputs in terms of hexadecimal format are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs " + + "contain non-hexadecimal characters.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with Roaming Consortium OIs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var wifiNAIRealmNamesGridChildInputs = "div#wifi-nai-realm-names .child-input"; + if ($(wifiNAIRealmNamesGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiNAIRealmNamesGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more NAI Realm Names are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with NAI Realm Names.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var wifiMCCAndMNCsGridChildInputs = "div#wifi-mcc-and-mncs .child-input"; + if ($(wifiMCCAndMNCsGridChildInputs).length > 0) { + var childInputCount = 0; + var stringPair; + emptyChildInputCount = 0; + outOfAllowedLengthCount = 0; + var notNumericInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiMCCAndMNCsGridChildInputs).each(function () { + childInput = $(this).val(); + // pushing each string pair to childInputArray + childInputCount++; + if (childInputCount % 2 == 1) { + // initialize stringPair value + stringPair = ""; + // append first part of the string + stringPair += childInput; + } else { + // append second part of the string + stringPair += childInput; + childInputArray.push(stringPair); + } + // updating emptyChildInputCount & outOfAllowedLengthCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!$.isNumeric(childInput)) { + notNumericInputCount++; + } else if (!inputIsValidAgainstLength(childInput, 3, 3)) { + outOfAllowedLengthCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (notNumericInputCount > 0) { + // if notNumeric input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs are not numeric.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (outOfAllowedLengthCount > 0) { + // if outOfAllowedLength input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs " + + "do not fulfill the accepted length of 6 digits.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with MCC/MNC pairs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating EMAIL + if ($.inArray(iosOperationConstants["EMAIL_OPERATION_CODE"], configuredOperations) != -1) { + // if EMAIL is configured + operation = iosOperationConstants["EMAIL_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var emailAddress = $("input#email-address").val(); + if (emailAddress && !inputIsValidAgainstRegExp(/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/, emailAddress)) { + validationStatus = { + "error": true, + "subErrorMsg": "Email Address is not valid.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var emailIncomingMailServerHostname = $("input#email-incoming-mail-server-hostname").val(); + if (!emailIncomingMailServerHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Hostname is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailIncomingMailServerPort = $("input#email-incoming-mail-server-port").val(); + if (emailIncomingMailServerPort && emailIncomingMailServerPort != '') { + if (!$.isNumeric(emailIncomingMailServerPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(emailIncomingMailServerPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var emailOutgoingMailServerHostname = $("input#email-outgoing-mail-server-hostname").val(); + if (!emailOutgoingMailServerHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Hostname is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailOutgoingMailServerPort = $("input#email-outgoing-mail-server-port").val(); + if (emailOutgoingMailServerPort && emailOutgoingMailServerPort != '') { + if (!$.isNumeric(emailOutgoingMailServerPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(emailOutgoingMailServerPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating AIRPLAY + if ($.inArray(iosOperationConstants["AIRPLAY_OPERATION_CODE"], configuredOperations) != -1) { + // if AIRPLAY is configured + operation = iosOperationConstants["AIRPLAY_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var airplayCredentialsGridChildInputs = "div#airplay-credentials .child-input"; + var airplayDestinationsGridChildInputs = "div#airplay-destinations .child-input"; + if ($(airplayCredentialsGridChildInputs).length == 0 && + $(airplayDestinationsGridChildInputs).length == 0) { + validationStatus = { + "error": true, + "subErrorMsg": "AirPlay settings have zero configurations attached.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + if ($(airplayCredentialsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(airplayCredentialsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 2 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Device Names of " + + "AirPlay Credentials are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "Device Names of AirPlay Credentials.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + if ($(airplayDestinationsGridChildInputs).length > 0) { + childInputArray = []; + emptyChildInputCount = 0; + invalidAgainstRegExCount = 0; + duplicatesExist = false; + // looping through each child input + $(airplayDestinationsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!inputIsValidAgainstRegExp( + /([a-z|A-Z|0-9][a-z|A-Z|0-9][:]){5}([a-z|A-Z|0-9][a-z|A-Z|0-9])$/, childInput)) { + // if child input field is invalid against RegEx + invalidAgainstRegExCount++ + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more AirPlay Destination fields are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (invalidAgainstRegExCount > 0) { + // if invalidAgainstRegEx inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more AirPlay Destination fields " + + "do not fulfill expected format.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with AirPlay Destinations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating LDAP + if ($.inArray(iosOperationConstants["LDAP_OPERATION_CODE"], configuredOperations) != -1) { + // if LDAP is configured + operation = iosOperationConstants["LDAP_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var ldapAccountHostname = $("input#ldap-account-hostname").val(); + if (!ldapAccountHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "LDAP Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var ldapSearchSettingsGridChildInputs = "div#ldap-search-settings .child-input"; + if ($(ldapSearchSettingsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(ldapSearchSettingsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 3 == 2) { + // if child input is of second column + childInput = $(this).find("option:selected").attr("value"); + stringPair = ""; + stringPair += (childInput + " "); + } else if (childInputCount % 3 == 0) { + // if child input is of third column + childInput = $(this).val(); + stringPair += childInput; + childInputArray.push(stringPair); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Search Setting Scope fields are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "Search Setting Search Base and Scope pairs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CALENDAR + if ($.inArray(iosOperationConstants["CALENDAR_OPERATION_CODE"], configuredOperations) != -1) { + // if CALENDAR is configured + operation = iosOperationConstants["CALENDAR_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var calendarAccountHostname = $("input#calendar-account-hostname").val(); + if (!calendarAccountHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var calendarAccountPort = $("input#calendar-account-port").val(); + if (!calendarAccountPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(calendarAccountPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(calendarAccountPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CALENDAR_SUBSCRIPTION + if ($.inArray(iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION_CODE"], configuredOperations) != -1) { + // if CALENDAR_SUBSCRIPTION is configured + operation = iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var calendarSubscriptionHostname = $("input#calendar-subscription-hostname").val(); + if (!calendarSubscriptionHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating APN + if ($.inArray(iosOperationConstants["APN_OPERATION_CODE"], configuredOperations) != -1) { + // if APN is configured + operation = iosOperationConstants["APN_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var apnConfigurationsGridChildInputs = "div#apn-configurations .child-input"; + if ($(apnConfigurationsGridChildInputs).length == 0) { + validationStatus = { + "error": true, + "subErrorMsg": "APN Settings have zero configurations attached.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if ($(apnConfigurationsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + // checking empty APN field count + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(apnConfigurationsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 5 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more APN fields of Configurations are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "APN fields of Configurations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CELLULAR + if ($.inArray(iosOperationConstants["CELLULAR_OPERATION_CODE"], configuredOperations) != -1) { + // if CELLULAR is configured + operation = iosOperationConstants["CELLULAR_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var cellularAttachAPNName = $("input#cellular-attach-apn-name").val(); + if (!cellularAttachAPNName) { + validationStatus = { + "error": true, + "subErrorMsg": "Cellular Configuration Name is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var cellularAPNConfigurationsGridChildInputs = "div#cellular-apn-configurations .child-input"; + if ($(cellularAPNConfigurationsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + // checking empty APN field count + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(cellularAPNConfigurationsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 6 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more APN fields of APN Configurations are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "APN fields of APN Configurations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + } + } + // ending validation process + + // start taking specific notifying actions upon validation + var wizardIsToBeContinued; + var errorCount = 0; + var mainErrorMsgWrapper, mainErrorMsg, + subErrorMsgWrapper, subErrorMsg, subErrorIcon, subOkIcon, featureConfiguredIcon; + var i; + for (i = 0; i < validationStatusArray.length; i++) { + validationStatus = validationStatusArray[i]; + if (validationStatus["error"]) { + errorCount++; + if (validationStatus["mainErrorMsg"]) { + mainErrorMsgWrapper = "#policy-profile-main-error-msg"; + mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else if (validationStatus["subErrorMsg"]) { + subErrorMsgWrapper = "#" + validationStatus["erroneousFeature"] + "-feature-error-msg"; + subErrorMsg = subErrorMsgWrapper + " span"; + subErrorIcon = "#" + validationStatus["erroneousFeature"] + "-error"; + subOkIcon = "#" + validationStatus["erroneousFeature"] + "-ok"; + featureConfiguredIcon = "#" + validationStatus["erroneousFeature"] + "-configured"; + // hiding featureConfiguredState as the first step + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // updating error state and corresponding messages + $(subErrorMsg).text(validationStatus["subErrorMsg"]); + if ($(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).removeClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if ($(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).removeClass("hidden"); + } + } + } else { + if (validationStatus["okFeature"]) { + subErrorMsgWrapper = "#" + validationStatus["okFeature"] + "-feature-error-msg"; + subErrorIcon = "#" + validationStatus["okFeature"] + "-error"; + subOkIcon = "#" + validationStatus["okFeature"] + "-ok"; + featureConfiguredIcon = "#" + validationStatus["okFeature"] + "-configured"; + // hiding featureConfiguredState as the first step + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // updating success state and corresponding messages + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if ($(subOkIcon).hasClass("hidden")) { + $(subOkIcon).removeClass("hidden"); + } + } + } + } + + wizardIsToBeContinued = (errorCount == 0); + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-profile"] = function () { + policy["profile"] = operationModule.generateProfile(policy["platform"], configuredOperations); + // updating next-page wizard title with selected platform + $("#policy-criteria-page-wizard-title").text("EDIT " + policy["platform"] + " POLICY - " + policy["name"]); + // updating ownership type options according to platform + if (policy["platform"] == platformTypeConstants["IOS"] || + policy["platform"] == platformTypeConstants["WINDOWS"]) { + var ownershipTypeSelectOptions = $("#ownership-input"); + ownershipTypeSelectOptions.empty(); + ownershipTypeSelectOptions.append($(""). + attr("value", "BYOD").text("BYOD (Bring Your Own Device)")); + ownershipTypeSelectOptions.attr("disabled", true); + } +}; + +stepForwardFrom["policy-criteria"] = function () { + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(':radio')) { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + policy["selectedUsers"] = $("#users-input").val(); + } else if ($(this).attr("id") == "user-roles-radio-btn") { + policy["selectedUserRoles"] = $("#user-roles-input").val(); + } + } + } + }); + policy["selectedNonCompliantAction"] = $("#action-input").find(":selected").data("action"); + policy["selectedOwnership"] = $("#ownership-input").val(); + // updating next-page wizard title with selected platform + $("#policy-naming-page-wizard-title").text("EDIT " + policy["platform"] + " POLICY - " + policy["name"]); +}; + +/** + * Checks if provided input is valid against provided length range. + * + * @param input Alphanumeric or non-alphanumeric input + * @param minLength Minimum Required Length + * @param maxLength Maximum Required Length + * @returns {boolean} Returns true if input matches the provided minimum length and maximum length + */ +var inputIsValidAgainstLength = function (input, minLength, maxLength) { + var length = input.length; + return (length == minLength || (length > minLength && length < maxLength) || length == maxLength); +}; + +validateStep["policy-criteria"] = function () { + var validationStatus = {}; + var selectedAssignees; + var selectedField = "Role(s)"; + + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + selectedAssignees = $("#users-input").val(); + selectedField = "User(s)"; + } else if ($(this).attr("id") == "user-roles-radio-btn") { + selectedAssignees = $("#user-roles-input").val(); + } + return false; + } + }); + + if (selectedAssignees) { + validationStatus["error"] = false; + } else { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = selectedField + " is a required field. It cannot be empty"; + } + + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-criteria-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-naming"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-naming-publish"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-naming-publish"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + updatePolicy(policy, "publish"); +}; +stepForwardFrom["policy-naming"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + updatePolicy(policy, "save"); +}; + +var updatePolicy = function (policy, state) { + var profilePayloads = []; + // traverses key by key in policy["profile"] + var key; + for (key in policy["profile"]) { + if (policy["platformId"] == platformTypeIds["WINDOWS"] && key == windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]) { + policy["profile"][key].enablePassword = true; + } + + if (policy["profile"].hasOwnProperty(key)) { + profilePayloads.push({ + "featureCode": key, + "deviceTypeId": policy["platformId"], + "content": policy["profile"][key] + }); + } + } + + $.each(profilePayloads, function (i, item) { + $.each(item.content, function (key, value) { + if (value === "" || value === undefined) { + item.content[key] = null; + } + }); + }); + + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": policy["selectedOwnership"], + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"] + }, + "profileFeaturesList": profilePayloads + } + }; + + if (policy["selectedUsers"]) { + payload["users"] = policy["selectedUsers"]; + } else if (policy["selectedUserRoles"]) { + payload["roles"] = policy["selectedUserRoles"]; + } else { + payload["users"] = []; + payload["roles"] = []; + } + + var serviceURL = "/devicemgt_admin/policies/" + getParameterByName("id"); + invokerUtil.put( + serviceURL, + payload, + // on success + function () { + if (state == "save") { + var policyList = []; + policyList.push(getParameterByName("id")); + serviceURL = "/devicemgt_admin/policies/inactivate"; + invokerUtil.put( + serviceURL, + policyList, + // on success + function () { + $(".add-policy").addClass("hidden"); + $(".policy-message").removeClass("hidden"); + }, + // on error + function (daa) { + console.log(data); + } + ); + } else if (state == "publish") { + var policyList = []; + policyList.push(getParameterByName("id")); + serviceURL = "/devicemgt_admin/policies/activate"; + invokerUtil.put( + serviceURL, + policyList, + // on success + function () { + $(".add-policy").addClass("hidden"); + $(".policy-naming").addClass("hidden"); + $(".policy-message").removeClass("hidden"); + }, + // on error + function (data) { + console.log(data); + } + ); + } + }, + // on error + function () { + + } + ); +}; + +// Start of HTML embedded invoke methods +var showAdvanceOperation = function (operation, button) { + $(button).addClass('selected'); + $(button).siblings().removeClass('selected'); + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="' + operation + '"]').show(); + $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide(); +}; + +/** + * Method to slide down a provided pane upon provided value set. + * + * @param selectElement Select HTML Element to consider + * @param paneID HTML ID of div element to slide down + * @param valueSet Applicable Value Set + */ +var slideDownPaneAgainstValueSet = function (selectElement, paneID, valueSet) { + var selectedValueOnChange = $(selectElement).find("option:selected").val(); + var i, slideDownVotes = 0; + for (i = 0; i < valueSet.length; i++) { + if (selectedValueOnChange == valueSet[i]) { + slideDownVotes++; + } + } + var paneSelector = "#" + paneID; + if (slideDownVotes > 0) { + if (!$(paneSelector).hasClass("expanded")) { + $(paneSelector).addClass("expanded"); + } + $(paneSelector).slideDown(); + } else { + if ($(paneSelector).hasClass("expanded")) { + $(paneSelector).removeClass("expanded"); + } + $(paneSelector).slideUp(); + /** now follows the code to reinitialize all inputs of the slidable pane */ + // reinitializing input fields into the defaults + $(paneSelector + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(paneSelector + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(paneSelector + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(paneSelector + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } +}; +// End of HTML embedded invoke methods + + +// Start of functions related to grid-input-view + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var setId = function (addFormContainer) { + $(addFormContainer).find("[data-add-form-clone]").each(function (i) { + $(this).attr("id", $(this).attr("data-add-form-clone").slice(1) + "-" + (i + 1)); + if ($(this).find(".index").length > 0) { + $(this).find(".index").html(i + 1); + } + }); +}; + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var showHideHelpText = function (addFormContainer) { + var helpText = "[data-help-text=add-form]"; + if ($(addFormContainer).find("[data-add-form-clone]").length > 0) { + $(addFormContainer).find(helpText).hide(); + } else { + $(addFormContainer).find(helpText).show(); + } +}; + +// End of functions related to grid-input-view + +/** + * This method will return query parameter value given its name. + * @param name Query parameter name + * @returns {string} Query parameter value + */ +var getParameterByName = function (name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); +}; + +function formatRepo(user) { + if (user.loading) { + return user.text + } + if (!user.username) { + return; + } + var markup = '
      ' + + '
      ' + + '
      ' + + '
      ' + user.username + '
      '; + if (user.firstname) { + markup += '
      ' + user.firstname + '
      '; + } + if (user.emailAddress) { + markup += '
      ' + user.emailAddress + '
      '; + } + markup += '
      '; + return markup; +} + +function formatRepoSelection(user) { + return user.username || user.text; +} + +$(document).ready(function () { + + // Adding initial state of wizard-steps. + + var policyPayloadObj; + invokerUtil.get( + "/devicemgt_admin/policies/" + getParameterByName("id"), + // on success + function (data) { + data = JSON.parse(data); + policyPayloadObj = data["responseContent"]; + skipStep["policy-platform"](policyPayloadObj); + }, + // on error + function (data) { + console.log(data); + // should be redirected to an error page + } + ); + + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + + $("input[type='radio'].select-users-radio").change(function () { + if ($("#users-radio-btn").is(":checked")) { + $("#user-roles-select-field").hide(); + $("#users-select-field").show(); + } + if ($("#user-roles-radio-btn").is(":checked")) { + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + } + }); + + // Support for special input type "ANY" on user(s) & user-role(s) selection + $("#user-roles-input,#user-input").select2({ + "tags": false + }).on("select2:select", function (e) { + if (e.params.data.id == "ANY") { + $(this).val("ANY").trigger("change"); + } else { + $("option[value=ANY]", this).prop("selected", false).parent().trigger("change"); + } + }); + $("#policy-profile-wizard-steps").html($(".wr-steps").html()); + + $("select.select2[multiple=multiple]").select2({ + "tags": false + }); + + // Maintains an array of configured features of the profile + var advanceOperations = ".wr-advance-operations"; + $(advanceOperations).on("click", ".wr-input-control.switch", function (event) { + var operationCode = $(this).parents(".operation-data").data("operation-code"); + var operation = $(this).parents(".operation-data").data("operation"); + var operationDataWrapper = $(this).data("target"); + // prevents event bubbling by figuring out what element it's being called from. + if (event.target.tagName == "INPUT") { + var featureConfiguredIcon; + if ($("input[type='checkbox']", this).is(":checked")) { + configuredOperations.push(operationCode); + // when a feature is enabled, if "zero-configured-features" msg is available, hide that. + var zeroConfiguredOperationsErrorMsg = "#policy-profile-main-error-msg"; + if (!$(zeroConfiguredOperationsErrorMsg).hasClass("hidden")) { + $(zeroConfiguredOperationsErrorMsg).addClass("hidden"); + } + // add configured-state-icon to the feature + featureConfiguredIcon = "#" + operation + "-configured"; + if ($(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).removeClass("hidden"); + } + } else { + //splicing the array if operation is present. + var index = $.inArray(operationCode, configuredOperations); + if (index != -1) { + configuredOperations.splice(index, 1); + } + // when a feature is disabled, clearing all its current configured, error or success states + var subErrorMsgWrapper = "#" + operation + "-feature-error-msg"; + var subErrorIcon = "#" + operation + "-error"; + var subOkIcon = "#" + operation + "-ok"; + featureConfiguredIcon = "#" + operation + "-configured"; + + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // reinitializing input fields into the defaults + $(operationDataWrapper + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(operationDataWrapper + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(operationDataWrapper + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(operationDataWrapper + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } + } + }); + + // adding support for cloning multiple profiles per feature with cloneable class definitions + $(advanceOperations).on("click", ".multi-view.add.enabled", function () { + // get a copy of .cloneable and create new .cloned div element + var cloned = "

      " + $(".cloneable", $(this).parent().parent()).html() + "
      "; + // append newly created .cloned div element to panel-body + $(this).parent().parent().append(cloned); + // enable remove action of newly cloned div element + $(".cloned", $(this).parent().parent()).each( + function () { + if ($(".multi-view.remove", this).hasClass("disabled")) { + $(".multi-view.remove", this).removeClass("disabled"); + } + if (!$(".multi-view.remove", this).hasClass("enabled")) { + $(".multi-view.remove", this).addClass("enabled"); + } + } + ); + }); + + $(advanceOperations).on("click", ".multi-view.remove.enabled", function () { + $(this).parent().remove(); + }); + + // enabling or disabling grouped-input based on the status of a parent check-box + $(advanceOperations).on("click", ".grouped-input", function () { + updateGroupedInputVisibility(this); + }); + + // add form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=add-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + var clonedForm = $("[data-add-form=" + $(this).attr("href") + "]").clone(). + find("[data-add-form-element=clone]").attr("data-add-form-clone", $(this).attr("href")); + + // adding class .child-input to capture text-input-array-values + $("input, select", clonedForm).addClass("child-input"); + + $(addFormContainer).append(clonedForm); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + // remove form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=remove-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + + $(this).closest("[data-add-form-element=clone]").remove(); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + $(".wizard-stepper").click(function () { + // button clicked here can be either a continue button or a back button. + var currentStep = $(this).data("current"); + var validationIsRequired = $(this).data("validate"); + var wizardIsToBeContinued; + + if (validationIsRequired) { + wizardIsToBeContinued = validateStep[currentStep](); + } else { + wizardIsToBeContinued = true; + } + + if (wizardIsToBeContinued) { + // When moving back and forth, following code segment will + // remove if there are any visible error-messages. + var errorMsgWrappers = ".alert.alert-danger"; + $(errorMsgWrappers).each( + function () { + if (!$(this).hasClass("hidden")) { + $(this).addClass("hidden"); + } + } + ); + + var nextStep = $(this).data("next"); + var isBackBtn = $(this).data("is-back-btn"); + + // if current button is a continuation... + if (!isBackBtn) { + // initiate stepForwardFrom[*] functions to gather form data. + if (stepForwardFrom[currentStep]) { + stepForwardFrom[currentStep](this); + } + } else { + // initiate stepBackFrom[*] functions to rollback. + if (stepBackFrom[currentStep]) { + stepBackFrom[currentStep](); + } + } + + // following step occurs only at the last stage of the wizard. + if (!nextStep) { + window.location.href = $(this).data("direct"); + } + + // updating next wizard step as current. + $(".itm-wiz").each(function () { + var step = $(this).data("step"); + if (step == nextStep) { + $(this).addClass("itm-wiz-current"); + } else { + $(this).removeClass("itm-wiz-current"); + } + }); + + // adding next update of wizard-steps. + $("#" + nextStep + "-wizard-steps").html($(".wr-steps").html()); + + // hiding current section of the wizard and showing next section. + $("." + currentStep).addClass("hidden"); + $("." + nextStep).removeClass("hidden"); + } + }); + +}); \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-android.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-android.hbs new file mode 100644 index 000000000..d82da3c0f --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-android.hbs @@ -0,0 +1,457 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable camera. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you do not need the device to be encrypted. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + + + + + + + + + + + + + + + + Please note that * sign represents required fields of data. +
      +
      + +
      + + +
      +
      + + +
      + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-ios.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-ios.hbs new file mode 100644 index 000000000..aec18bda8 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-ios.hbs @@ -0,0 +1,2923 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + + + +
      + + +
      + + + +
      + +
      + + + + + + + + + + + + + +
      No:Roaming Consortium OI
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + +
      No:NAI Realm Name
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + + +
      No:Mobile Country Code ( MCC )Mobile Network Code ( MNC )
      + No entries added yet . +
      + + + + + + + + + + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + Incoming Mail Settings : +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + Outgoing Mail Settings : +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + +
      + + + + + + + + + + + + + + +
      No:Device NamePassword
      + No entries added yet . +
      + + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + +
      No:Destination
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + + + + + + + + + + + + + + + +
      No:DescriptionSearch BaseScope
      + No entries added yet . +
      + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      No:APNUsernamePasswordProxyPort
      + No entries added yet . +
      + + + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + + + + + + + + + + + + + + + + + + +
      No:APNAuth.TypeUsernamePasswordProxyPort
      + No entries added yet . +
      + + + + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + + Restrictions on Device Functionality : +
      +
      +
        +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
          +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      +
      +
      + Restrictions on Applications : +
      +
      +
        +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
          +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + + +
          +
        • +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      +
      + + + +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-windows.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-windows.hbs new file mode 100644 index 000000000..3b5bb3bef --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.edit/public/templates/hidden-operations-windows.hbs @@ -0,0 +1,460 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable camera. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable storage-encryption. +
      +
      +
      + +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/js/policy-view.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/js/policy-view.js new file mode 100644 index 000000000..8ca8ff879 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/js/policy-view.js @@ -0,0 +1,2256 @@ +/* + * 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. + */ + +var validateStep = {}; +var skipStep = {}; +var stepForwardFrom = {}; +var stepBackFrom = {}; +var policy = {}; +var configuredOperations = []; + +// Constants to define platform types available +var platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" +}; + +// Constants to define Android Operation Constants +var androidOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION": "camera", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION": "encrypt-storage", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE", + "WIFI_OPERATION": "wifi", + "WIFI_OPERATION_CODE": "WIFI" +}; + +// Constants to define Android Operation Constants +var windowsOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION": "camera", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION": "encrypt-storage", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE" +}; + +// Constants to define iOS Operation Constants +var iosOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "RESTRICTIONS_OPERATION": "restrictions", + "RESTRICTIONS_OPERATION_CODE": "RESTRICTION", + "WIFI_OPERATION": "wifi", + "WIFI_OPERATION_CODE": "WIFI", + "EMAIL_OPERATION": "email", + "EMAIL_OPERATION_CODE": "EMAIL", + "AIRPLAY_OPERATION": "airplay", + "AIRPLAY_OPERATION_CODE": "AIR_PLAY", + "LDAP_OPERATION": "ldap", + "LDAP_OPERATION_CODE": "LDAP", + "CALENDAR_OPERATION": "calendar", + "CALENDAR_OPERATION_CODE": "CALDAV", + "CALENDAR_SUBSCRIPTION_OPERATION": "calendar-subscription", + "CALENDAR_SUBSCRIPTION_OPERATION_CODE": "CALENDAR_SUBSCRIPTION", + "APN_OPERATION": "apn", + "APN_OPERATION_CODE": "APN", + "CELLULAR_OPERATION": "cellular", + "CELLULAR_OPERATION_CODE": "CELLULAR" +}; + +/** + * Method to update the visibility (i.e. disabled or enabled view) + * of grouped input according to the values + * that they currently possess. + * @param domElement HTML grouped-input element with class name "grouped-input" + */ +var updateGroupedInputVisibility = function (domElement) { + if ($(".parent-input:first", domElement).is(":checked")) { + if ($(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).removeClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', false); + }); + } else { + if (!$(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).addClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', true); + }); + } +}; + +skipStep["policy-platform"] = function (policyPayloadObj) { + policy["name"] = policyPayloadObj["policyName"]; + policy["platform"] = policyPayloadObj["profile"]["deviceType"]["name"]; + policy["platformId"] = policyPayloadObj["profile"]["deviceType"]["id"]; + var userRoleInput = $("#user-roles-input"); + var ownershipInput = $("#ownership-input"); + var userInput = $("#users-select-field"); + var actionInput = $("#action-input"); + var policyNameInput = $("#policy-name-input"); + var policyDescriptionInput = $("#policy-description-input"); + userRoleInput.val(policyPayloadObj.roles); + userInput.val(policyPayloadObj.users); + ownershipInput.val(policyPayloadObj.ownershipType); + actionInput.val(policyPayloadObj.compliance); + policyNameInput.val(policyPayloadObj["policyName"]); + policyDescriptionInput.val(policyPayloadObj["description"]); + // updating next-page wizard title with selected platform + $("#policy-heading").text(policy["platform"].toUpperCase() + " POLICY - " + policy["name"].toUpperCase()); + $("#policy-platform").text(policy["platform"].toUpperCase()); + $("#policy-assignment").text(policyPayloadObj.ownershipType); + $("#policy-action").text(policyPayloadObj.compliance.toUpperCase()); + $("#policy-description").text(policyPayloadObj["description"]); + var policyStatus = "Active"; + if (policyPayloadObj["active"] == true && policyPayloadObj["updated"] == true) { + policyStatus = ' Active/Updated'; + } else if (policyPayloadObj["active"] == true && policyPayloadObj["updated"] == false) { + policyStatus = ' Active'; + } else if (policyPayloadObj["active"] == false && policyPayloadObj["updated"] == true) { + policyStatus = ' Inactive/Updated'; + } else if (policyPayloadObj["active"] == false && policyPayloadObj["updated"] == false) { + policyStatus = ' Inactive'; + } + + $("#policy-status").html(policyStatus); + + if (policyPayloadObj.users.length > 0) { + $("#policy-users").text(policyPayloadObj.users.toString().split(",").join(", ")); + } else { + $("#users-row").addClass("hidden"); + } + + if (policyPayloadObj.roles.length > 0) { + $("#policy-roles").text(policyPayloadObj.roles.toString().split(",").join(", ")); + } else { + $("#roles-row").addClass("hidden"); + } + + var deviceType = policy["platform"]; + var hiddenOperationsByDeviceType = $("#hidden-operations-" + deviceType); + var hiddenOperationsByDeviceTypeCacheKey = deviceType + "HiddenOperations"; + var hiddenOperationsByDeviceTypeSrc = hiddenOperationsByDeviceType.attr("src"); + + setTimeout( + function () { + $.template(hiddenOperationsByDeviceTypeCacheKey, hiddenOperationsByDeviceTypeSrc, function (template) { + var content = template(); + // pushing profile feature input elements + $(".wr-advance-operations").html(content); + // populating values and getting the list of configured features + var configuredOperations = operationModule. + populateProfile(policy["platform"], policyPayloadObj["profile"]["profileFeaturesList"]); + // updating grouped input visibility according to the populated values + $(".wr-advance-operations li.grouped-input").each(function () { + updateGroupedInputVisibility(this); + }); + // enabling previously configured options of last update + for (var i = 0; i < configuredOperations.length; ++i) { + var configuredOperation = configuredOperations[i]; + $(".operation-data").filterByData("operation-code", configuredOperation). + find(".panel-title .wr-input-control.switch input[type=checkbox]").each(function () { + $(this).click(); + }); + } + }); + }, + 250 // time delayed for the execution of above function, 250 milliseconds + ); +}; + +/** + * Checks if provided number is valid against a range. + * + * @param numberInput Number Input + * @param min Minimum Limit + * @param max Maximum Limit + * @returns {boolean} Returns true if input is within the specified range + */ +var inputIsValidAgainstRange = function (numberInput, min, max) { + return (numberInput == min || (numberInput > min && numberInput < max) || numberInput == max); +}; + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param input Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +var inputIsValidAgainstRegExp = function (regExp, input) { + return regExp.test(input); +}; + +validateStep["policy-profile"] = function () { + var validationStatusArray = []; + var validationStatus; + var operation; + + // starting validation process and updating validationStatus + if (policy["platform"] == platformTypeConstants["ANDROID"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(androidOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = androidOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + var continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + var passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + var passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CAMERA + if ($.inArray(androidOperationConstants["CAMERA_OPERATION_CODE"], configuredOperations) != -1) { + // if CAMERA is configured + operation = androidOperationConstants["CAMERA_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating ENCRYPT_STORAGE + if ($.inArray(androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"], configuredOperations) != -1) { + // if ENCRYPT_STORAGE is configured + operation = androidOperationConstants["ENCRYPT_STORAGE_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating WIFI + if ($.inArray(androidOperationConstants["WIFI_OPERATION_CODE"], configuredOperations) != -1) { + // if WIFI is configured + operation = androidOperationConstants["WIFI_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var wifiSSID = $("input#wifi-ssid").val(); + if (!wifiSSID) { + validationStatus = { + "error": true, + "subErrorMsg": "WIFI SSID is not given. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + } + } + if (policy["platform"] == platformTypeConstants["WINDOWS"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = windowsOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + var continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + var passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + var passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CAMERA + if ($.inArray(windowsOperationConstants["CAMERA_OPERATION_CODE"], configuredOperations) != -1) { + // if CAMERA is configured + operation = windowsOperationConstants["CAMERA_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating ENCRYPT_STORAGE + if ($.inArray(windowsOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"], configuredOperations) != -1) { + // if ENCRYPT_STORAGE is configured + operation = windowsOperationConstants["ENCRYPT_STORAGE_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + + } + } else if (policy["platform"] == platformTypeConstants["IOS"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(iosOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = iosOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating RESTRICTIONS + if ($.inArray(iosOperationConstants["RESTRICTIONS_OPERATION_CODE"], configuredOperations) != -1) { + // if RESTRICTION is configured + operation = iosOperationConstants["RESTRICTIONS_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // getting input values to be validated + var restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs = + "div#restrictions-autonomous-single-app-mode-permitted-app-ids .child-input"; + if ($(restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs).length > 0) { + var childInput; + var childInputArray = []; + var emptyChildInputCount = 0; + var duplicatesExist = false; + // looping through each child input + $(restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + var initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + var m, poppedChildInput; + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + var n; + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more permitted App ID entries in " + + "Autonomous Single App Mode are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with permitted App ID entries in " + + "Autonomous Single App Mode.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating WIFI + if ($.inArray(iosOperationConstants["WIFI_OPERATION_CODE"], configuredOperations) != -1) { + // if WIFI is configured + operation = iosOperationConstants["WIFI_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // getting input values to be validated + wifiSSID = $("input#wifi-ssid").val(); + var wifiDomainName = $("input#wifi-domain-name").val(); + if (!wifiSSID && !wifiDomainName) { + validationStatus = { + "error": true, + "subErrorMsg": "Both Wi-Fi SSID and Wi-Fi Domain Name are not given. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + // getting proxy-setup value + var wifiProxyType = $("select#wifi-proxy-type").find("option:selected").attr("value"); + if (wifiProxyType == "Manual") { + // adds up additional fields to be validated + var wifiProxyServer = $("input#wifi-proxy-server").val(); + if (!wifiProxyServer) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Server is required. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var wifiProxyPort = $("input#wifi-proxy-port").val(); + if (!wifiProxyPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port is required. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(wifiProxyPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(wifiProxyPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + } + + if (continueToCheckNextInputs) { + // getting encryption-type value + var wifiEncryptionType = $("select#wifi-encryption-type").find("option:selected").attr("value"); + if (wifiEncryptionType != "None") { + var wifiPayloadCertificateAnchorUUIDsGridChildInputs = + "div#wifi-payload-certificate-anchor-uuids .child-input"; + if ($(wifiPayloadCertificateAnchorUUIDsGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiPayloadCertificateAnchorUUIDsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Payload Certificate " + + "Anchor UUIDs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist " + + "with Payload Certificate Anchor UUIDs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var wifiTLSTrustedServerNamesGridChildInputs = + "div#wifi-tls-trusted-server-names .child-input"; + if ($(wifiTLSTrustedServerNamesGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiTLSTrustedServerNamesGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more TLS Trusted Server Names are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist " + + "with TLS Trusted Server Names.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + } + } + + if (continueToCheckNextInputs) { + var wifiRoamingConsortiumOIsGridChildInputs = "div#wifi-roaming-consortium-ois .child-input"; + if ($(wifiRoamingConsortiumOIsGridChildInputs).length > 0) { + emptyChildInputCount = 0; + var outOfAllowedLengthCount = 0; + var invalidAgainstRegExCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiRoamingConsortiumOIsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!inputIsValidAgainstLength(childInput, 6, 6) && !inputIsValidAgainstLength(childInput, 10, 10)) { + outOfAllowedLengthCount++; + } else if (!inputIsValidAgainstRegExp(/^[a-fA-F0-9]+$/, childInput)) { + invalidAgainstRegExCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (outOfAllowedLengthCount > 0) { + // if outOfMaxAllowedLength input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs " + + "are out of allowed length.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (invalidAgainstRegExCount > 0) { + // if invalid inputs in terms of hexadecimal format are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs " + + "contain non-hexadecimal characters.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with Roaming Consortium OIs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var wifiNAIRealmNamesGridChildInputs = "div#wifi-nai-realm-names .child-input"; + if ($(wifiNAIRealmNamesGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiNAIRealmNamesGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more NAI Realm Names are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with NAI Realm Names.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var wifiMCCAndMNCsGridChildInputs = "div#wifi-mcc-and-mncs .child-input"; + if ($(wifiMCCAndMNCsGridChildInputs).length > 0) { + var childInputCount = 0; + var stringPair; + emptyChildInputCount = 0; + outOfAllowedLengthCount = 0; + var notNumericInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiMCCAndMNCsGridChildInputs).each(function () { + childInput = $(this).val(); + // pushing each string pair to childInputArray + childInputCount++; + if (childInputCount % 2 == 1) { + // initialize stringPair value + stringPair = ""; + // append first part of the string + stringPair += childInput; + } else { + // append second part of the string + stringPair += childInput; + childInputArray.push(stringPair); + } + // updating emptyChildInputCount & outOfAllowedLengthCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!$.isNumeric(childInput)) { + notNumericInputCount++; + } else if (!inputIsValidAgainstLength(childInput, 3, 3)) { + outOfAllowedLengthCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (notNumericInputCount > 0) { + // if notNumeric input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs are not numeric.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (outOfAllowedLengthCount > 0) { + // if outOfAllowedLength input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs " + + "do not fulfill the accepted length of 6 digits.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with MCC/MNC pairs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating EMAIL + if ($.inArray(iosOperationConstants["EMAIL_OPERATION_CODE"], configuredOperations) != -1) { + // if EMAIL is configured + operation = iosOperationConstants["EMAIL_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var emailAddress = $("input#email-address").val(); + if (emailAddress && !inputIsValidAgainstRegExp(/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/, emailAddress)) { + validationStatus = { + "error": true, + "subErrorMsg": "Email Address is not valid.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var emailIncomingMailServerHostname = $("input#email-incoming-mail-server-hostname").val(); + if (!emailIncomingMailServerHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Hostname is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailIncomingMailServerPort = $("input#email-incoming-mail-server-port").val(); + if (!emailIncomingMailServerPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(emailIncomingMailServerPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(emailIncomingMailServerPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailOutgoingMailServerHostname = $("input#email-outgoing-mail-server-hostname").val(); + if (!emailOutgoingMailServerHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Hostname is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailOutgoingMailServerPort = $("input#email-outgoing-mail-server-port").val(); + if (!emailOutgoingMailServerPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(emailOutgoingMailServerPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(emailOutgoingMailServerPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating AIRPLAY + if ($.inArray(iosOperationConstants["AIRPLAY_OPERATION_CODE"], configuredOperations) != -1) { + // if AIRPLAY is configured + operation = iosOperationConstants["AIRPLAY_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var airplayCredentialsGridChildInputs = "div#airplay-credentials .child-input"; + var airplayDestinationsGridChildInputs = "div#airplay-destinations .child-input"; + if ($(airplayCredentialsGridChildInputs).length == 0 && + $(airplayDestinationsGridChildInputs).length == 0) { + validationStatus = { + "error": true, + "subErrorMsg": "AirPlay settings have zero configurations attached.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + if ($(airplayCredentialsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(airplayCredentialsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 2 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Device Names of " + + "AirPlay Credentials are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "Device Names of AirPlay Credentials.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + if ($(airplayDestinationsGridChildInputs).length > 0) { + childInputArray = []; + emptyChildInputCount = 0; + invalidAgainstRegExCount = 0; + duplicatesExist = false; + // looping through each child input + $(airplayDestinationsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!inputIsValidAgainstRegExp( + /([a-z|A-Z|0-9][a-z|A-Z|0-9][:]){5}([a-z|A-Z|0-9][a-z|A-Z|0-9])$/, childInput)) { + // if child input field is invalid against RegEx + invalidAgainstRegExCount++ + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more AirPlay Destination fields are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (invalidAgainstRegExCount > 0) { + // if invalidAgainstRegEx inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more AirPlay Destination fields " + + "do not fulfill expected format.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with AirPlay Destinations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating LDAP + if ($.inArray(iosOperationConstants["LDAP_OPERATION_CODE"], configuredOperations) != -1) { + // if LDAP is configured + operation = iosOperationConstants["LDAP_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var ldapAccountHostname = $("input#ldap-account-hostname").val(); + if (!ldapAccountHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "LDAP Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var ldapSearchSettingsGridChildInputs = "div#ldap-search-settings .child-input"; + if ($(ldapSearchSettingsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(ldapSearchSettingsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 3 == 2) { + // if child input is of second column + childInput = $(this).find("option:selected").attr("value"); + stringPair = ""; + stringPair += (childInput + " "); + } else if (childInputCount % 3 == 0) { + // if child input is of third column + childInput = $(this).val(); + stringPair += childInput; + childInputArray.push(stringPair); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Search Setting Scope fields are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "Search Setting Search Base and Scope pairs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CALENDAR + if ($.inArray(iosOperationConstants["CALENDAR_OPERATION_CODE"], configuredOperations) != -1) { + // if CALENDAR is configured + operation = iosOperationConstants["CALENDAR_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var calendarAccountHostname = $("input#calendar-account-hostname").val(); + if (!calendarAccountHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var calendarAccountPort = $("input#calendar-account-port").val(); + if (!calendarAccountPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(calendarAccountPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(calendarAccountPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CALENDAR_SUBSCRIPTION + if ($.inArray(iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION_CODE"], configuredOperations) != -1) { + // if CALENDAR_SUBSCRIPTION is configured + operation = iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var calendarSubscriptionHostname = $("input#calendar-subscription-hostname").val(); + if (!calendarSubscriptionHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating APN + if ($.inArray(iosOperationConstants["APN_OPERATION_CODE"], configuredOperations) != -1) { + // if APN is configured + operation = iosOperationConstants["APN_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var apnConfigurationsGridChildInputs = "div#apn-configurations .child-input"; + if ($(apnConfigurationsGridChildInputs).length == 0) { + validationStatus = { + "error": true, + "subErrorMsg": "APN Settings have zero configurations attached.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if ($(apnConfigurationsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + // checking empty APN field count + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(apnConfigurationsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 5 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more APN fields of Configurations are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "APN fields of Configurations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CELLULAR + if ($.inArray(iosOperationConstants["CELLULAR_OPERATION_CODE"], configuredOperations) != -1) { + // if CELLULAR is configured + operation = iosOperationConstants["CELLULAR_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var cellularAttachAPNName = $("input#cellular-attach-apn-name").val(); + if (!cellularAttachAPNName) { + validationStatus = { + "error": true, + "subErrorMsg": "Cellular Configuration Name is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var cellularAPNConfigurationsGridChildInputs = "div#cellular-apn-configurations .child-input"; + if ($(cellularAPNConfigurationsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + // checking empty APN field count + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(cellularAPNConfigurationsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 6 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more APN fields of APN Configurations are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "APN fields of APN Configurations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + } + } + // ending validation process + + // start taking specific notifying actions upon validation + var wizardIsToBeContinued; + var errorCount = 0; + var mainErrorMsgWrapper, mainErrorMsg, + subErrorMsgWrapper, subErrorMsg, subErrorIcon, subOkIcon, featureConfiguredIcon; + var i; + for (i = 0; i < validationStatusArray.length; i++) { + validationStatus = validationStatusArray[i]; + if (validationStatus["error"]) { + errorCount++; + if (validationStatus["mainErrorMsg"]) { + mainErrorMsgWrapper = "#policy-profile-main-error-msg"; + mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else if (validationStatus["subErrorMsg"]) { + subErrorMsgWrapper = "#" + validationStatus["erroneousFeature"] + "-feature-error-msg"; + subErrorMsg = subErrorMsgWrapper + " span"; + subErrorIcon = "#" + validationStatus["erroneousFeature"] + "-error"; + subOkIcon = "#" + validationStatus["erroneousFeature"] + "-ok"; + featureConfiguredIcon = "#" + validationStatus["erroneousFeature"] + "-configured"; + // hiding featureConfiguredState as the first step + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // updating error state and corresponding messages + $(subErrorMsg).text(validationStatus["subErrorMsg"]); + if ($(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).removeClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if ($(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).removeClass("hidden"); + } + } + } else { + if (validationStatus["okFeature"]) { + subErrorMsgWrapper = "#" + validationStatus["okFeature"] + "-feature-error-msg"; + subErrorIcon = "#" + validationStatus["okFeature"] + "-error"; + subOkIcon = "#" + validationStatus["okFeature"] + "-ok"; + featureConfiguredIcon = "#" + validationStatus["okFeature"] + "-configured"; + // hiding featureConfiguredState as the first step + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // updating success state and corresponding messages + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if ($(subOkIcon).hasClass("hidden")) { + $(subOkIcon).removeClass("hidden"); + } + } + } + } + + wizardIsToBeContinued = (errorCount == 0); + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-profile"] = function () { + policy["profile"] = operationModule.generateProfile(policy["platform"], configuredOperations); + // updating next-page wizard title with selected platform + $("#policy-criteria-page-wizard-title").text(policy["platform"] + " POLICY - " + policy["name"]); +}; + +stepForwardFrom["policy-criteria"] = function () { + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(':radio')) { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + policy["selectedUsers"] = $("#users-input").val(); + } else if ($(this).attr("id") == "user-roles-radio-btn") { + policy["selectedUserRoles"] = $("#user-roles-input").val(); + } + } + } + }); + policy["selectedNonCompliantAction"] = $("#action-input").find(":selected").data("action"); + policy["selectedOwnership"] = $("#ownership-input").val(); + // updating next-page wizard title with selected platform + $("#policy-naming-page-wizard-title").text(policy["platform"] + " POLICY - " + policy["name"]); +}; + +/** + * Checks if provided input is valid against provided length range. + * + * @param input Alphanumeric or non-alphanumeric input + * @param minLength Minimum Required Length + * @param maxLength Maximum Required Length + * @returns {boolean} Returns true if input matches the provided minimum length and maximum length + */ +var inputIsValidAgainstLength = function (input, minLength, maxLength) { + var length = input.length; + return (length == minLength || (length > minLength && length < maxLength) || length == maxLength); +}; + +validateStep["policy-naming"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-naming-publish"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-naming-publish"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + updatePolicy(policy, "publish"); +}; +stepForwardFrom["policy-naming"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + updatePolicy(policy, "save"); +}; + +var updatePolicy = function (policy, state) { + var profilePayloads = []; + // traverses key by key in policy["profile"] + var key; + for (key in policy["profile"]) { + if (policy["profile"].hasOwnProperty(key)) { + profilePayloads.push({ + "featureCode": key, + "deviceTypeId": policy["platformId"], + "content": policy["profile"][key] + }); + } + } + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": policy["selectedOwnership"], + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"] + }, + "profileFeaturesList": profilePayloads + } + }; + + if (policy["selectedUsers"]) { + payload["users"] = policy["selectedUsers"]; + } else if (policy["selectedUserRoles"]) { + payload["roles"] = policy["selectedUserRoles"]; + } else { + payload["users"] = []; + payload["roles"] = []; + } + var serviceURL = "/devicemgt_admin/policies/" + getParameterByName("id"); + invokerUtil.put( + serviceURL, + payload, + // on success + function () { + if (state == "save") { + var policyList = []; + policyList.push(getParameterByName("id")); + serviceURL = "/devicemgt_admin/policies/inactivate"; + invokerUtil.put( + serviceURL, + policyList, + // on success + function () { + $(".policy-message").removeClass("hidden"); + $(".add-policy").addClass("hidden"); + }, + // on error + function (data) { + console.log(data); + } + ); + } else if (state == "publish") { + var policyList = []; + policyList.push(getParameterByName("id")); + serviceURL = "/devicemgt_admin/policies/activate"; + invokerUtil.put( + serviceURL, + policyList, + // on success + function () { + $(".policy-message").removeClass("hidden"); + $(".add-policy").addClass("hidden"); + }, + // on error + function (data) { + console.log(data); + } + ); + } + }, + // on error + function (data) { + console.log(data); + } + ); +}; + +// Start of HTML embedded invoke methods +var showAdvanceOperation = function (operation, button) { + $(button).addClass('selected'); + $(button).siblings().removeClass('selected'); + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="' + operation + '"]').show(); + $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide(); +}; + +/** + * Method to slide down a provided pane upon provided value set. + * + * @param selectElement Select HTML Element to consider + * @param paneID HTML ID of div element to slide down + * @param valueSet Applicable Value Set + */ +var slideDownPaneAgainstValueSet = function (selectElement, paneID, valueSet) { + var selectedValueOnChange = $(selectElement).find("option:selected").val(); + var i, slideDownVotes = 0; + for (i = 0; i < valueSet.length; i++) { + if (selectedValueOnChange == valueSet[i]) { + slideDownVotes++; + } + } + var paneSelector = "#" + paneID; + if (slideDownVotes > 0) { + if (!$(paneSelector).hasClass("expanded")) { + $(paneSelector).addClass("expanded"); + } + $(paneSelector).slideDown(); + } else { + if ($(paneSelector).hasClass("expanded")) { + $(paneSelector).removeClass("expanded"); + } + $(paneSelector).slideUp(); + /* now follows the code to reinitialize all inputs of the slidable pane. + reinitializing input fields into the defaults.*/ + $(paneSelector + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(paneSelector + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(paneSelector + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(paneSelector + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } +}; +// End of HTML embedded invoke methods + + +// Start of functions related to grid-input-view + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var setId = function (addFormContainer) { + $(addFormContainer).find("[data-add-form-clone]").each(function (i) { + $(this).attr("id", $(this).attr("data-add-form-clone").slice(1) + "-" + (i + 1)); + if ($(this).find(".index").length > 0) { + $(this).find(".index").html(i + 1); + } + }); +}; + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var showHideHelpText = function (addFormContainer) { + var helpText = "[data-help-text=add-form]"; + if ($(addFormContainer).find("[data-add-form-clone]").length > 0) { + $(addFormContainer).find(helpText).hide(); + } else { + $(addFormContainer).find(helpText).show(); + } +}; + +// End of functions related to grid-input-view + +/** + * This method will return query parameter value given its name. + * @param name Query parameter name + * @returns {string} Query parameter value + */ +var getParameterByName = function (name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); +}; + +$(document).ready(function () { + $('#appbar-btn-apply-changes').addClass('hidden'); + // Adding initial state of wizard-steps. + $("#policy-profile-wizard-steps").html($(".wr-steps").html()); + + var policyPayloadObj; + invokerUtil.get( + "/devicemgt_admin/policies/" + getParameterByName("id"), + // on success + function (data) { + // console.log("success: " + JSON.stringify(data)); + data = JSON.parse(data); + policyPayloadObj = data["responseContent"]; + skipStep["policy-platform"](policyPayloadObj); + }, + // on error + function (data) { + console.log(data); + // should be redirected to an error page + } + ); + + $("select.select2[multiple=multiple]").select2({ + "tags": true + }); + + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + + $("input[type='radio'].select-users-radio").change(function () { + if ($("#users-radio-btn").is(":checked")) { + $("#user-roles-select-field").hide(); + $("#users-select-field").show(); + } + if ($("#user-roles-radio-btn").is(":checked")) { + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + } + }); + + // Support for special input type "ANY" on user(s) & user-role(s) selection + $("#users-input, #user-roles-input").select2({ + "tags": true + }).on("select2:select", function (e) { + if (e.params.data.id == "ANY") { + $(this).val("ANY").trigger("change"); + } else { + $("option[value=ANY]", this).prop("selected", false).parent().trigger("change"); + } + }); + + // Maintains an array of configured features of the profile + var advanceOperations = ".wr-advance-operations"; + $(advanceOperations).on("click", ".wr-input-control.switch", function (event) { + var operationCode = $(this).parents(".operation-data").data("operation-code"); + var operation = $(this).parents(".operation-data").data("operation"); + var operationDataWrapper = $(this).data("target"); + // prevents event bubbling by figuring out what element it's being called from. + if (event.target.tagName == "INPUT") { + var featureConfiguredIcon; + if ($("input[type='checkbox']", this).is(":checked")) { + configuredOperations.push(operationCode); + // when a feature is enabled, if "zero-configured-features" msg is available, hide that. + var zeroConfiguredOperationsErrorMsg = "#policy-profile-main-error-msg"; + if (!$(zeroConfiguredOperationsErrorMsg).hasClass("hidden")) { + $(zeroConfiguredOperationsErrorMsg).addClass("hidden"); + } + // add configured-state-icon to the feature + featureConfiguredIcon = "#" + operation + "-configured"; + if ($(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).removeClass("hidden"); + } + } else { + //splicing the array if operation is present. + var index = $.inArray(operationCode, configuredOperations); + if (index != -1) { + configuredOperations.splice(index, 1); + } + // when a feature is disabled, clearing all its current configured, error or success states + var subErrorMsgWrapper = "#" + operation + "-feature-error-msg"; + var subErrorIcon = "#" + operation + "-error"; + var subOkIcon = "#" + operation + "-ok"; + featureConfiguredIcon = "#" + operation + "-configured"; + + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // reinitializing input fields into the defaults + $(operationDataWrapper + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(operationDataWrapper + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(operationDataWrapper + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(operationDataWrapper + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } + } + }); + + // adding support for cloning multiple profiles per feature with cloneable class definitions + $(advanceOperations).on("click", ".multi-view.add.enabled", function () { + // get a copy of .cloneable and create new .cloned div element + var cloned = "

      " + $(".cloneable", $(this).parent().parent()).html() + "
      "; + // append newly created .cloned div element to panel-body + $(this).parent().parent().append(cloned); + // enable remove action of newly cloned div element + $(".cloned", $(this).parent().parent()).each( + function () { + if ($(".multi-view.remove", this).hasClass("disabled")) { + $(".multi-view.remove", this).removeClass("disabled"); + } + if (!$(".multi-view.remove", this).hasClass("enabled")) { + $(".multi-view.remove", this).addClass("enabled"); + } + } + ); + }); + + $(advanceOperations).on("click", ".multi-view.remove.enabled", function () { + $(this).parent().remove(); + }); + + // enabling or disabling grouped-input based on the status of a parent check-box + $(advanceOperations).on("click", ".grouped-input", function () { + updateGroupedInputVisibility(this); + }); + + // add form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=add-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + var clonedForm = $("[data-add-form=" + $(this).attr("href") + "]").clone(). + find("[data-add-form-element=clone]").attr("data-add-form-clone", $(this).attr("href")); + + // adding class .child-input to capture text-input-array-values + $("input, select", clonedForm).addClass("child-input"); + + $(addFormContainer).append(clonedForm); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + // remove form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=remove-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + + $(this).closest("[data-add-form-element=clone]").remove(); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + $(".wizard-stepper").click(function () { + // button clicked here can be either a continue button or a back button. + var currentStep = $(this).data("current"); + var validationIsRequired = $(this).data("validate"); + var wizardIsToBeContinued; + + if (validationIsRequired) { + wizardIsToBeContinued = validateStep[currentStep](); + } else { + wizardIsToBeContinued = true; + } + + if (wizardIsToBeContinued) { + // When moving back and forth, following code segment will + // remove if there are any visible error-messages. + var errorMsgWrappers = ".alert.alert-danger"; + $(errorMsgWrappers).each( + function () { + if (!$(this).hasClass("hidden")) { + $(this).addClass("hidden"); + } + } + ); + + var nextStep = $(this).data("next"); + var isBackBtn = $(this).data("is-back-btn"); + + // if current button is a continuation... + if (!isBackBtn) { + // initiate stepForwardFrom[*] functions to gather form data. + if (stepForwardFrom[currentStep]) { + stepForwardFrom[currentStep](this); + } + } else { + // initiate stepBackFrom[*] functions to rollback. + if (stepBackFrom[currentStep]) { + stepBackFrom[currentStep](); + } + } + + // following step occurs only at the last stage of the wizard. + if (!nextStep) { + window.location.href = $(this).data("direct"); + } + + // updating next wizard step as current. + $(".itm-wiz").each(function () { + var step = $(this).data("step"); + if (step == nextStep) { + $(this).addClass("itm-wiz-current"); + } else { + $(this).removeClass("itm-wiz-current"); + } + }); + + // adding next update of wizard-steps. + $("#" + nextStep + "-wizard-steps").html($(".wr-steps").html()); + + // hiding current section of the wizard and showing next section. + $("." + currentStep).addClass("hidden"); + $("." + nextStep).removeClass("hidden"); + } + }); +}); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-android.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-android.hbs new file mode 100644 index 000000000..80932391a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-android.hbs @@ -0,0 +1,439 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable camera. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you do not need the device to be encrypted. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + + + + + + + + + + + + + + + + Please note that * sign represents required fields of data. +
      +
      + +
      + + +
      +
      + + +
      + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-ios.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-ios.hbs new file mode 100644 index 000000000..4aeed0646 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-ios.hbs @@ -0,0 +1,2923 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + + + +
      + + +
      + + + +
      + +
      + + + + + + + + + + + + + +
      No:Roaming Consortium OI
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + +
      No:NAI Realm Name
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + + +
      No:Mobile Country Code ( MCC )Mobile Network Code ( MNC )
      + No entries added yet . +
      + + + + + + + + + + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + Incoming Mail Settings : +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + Outgoing Mail Settings : +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + +
      + + + + + + + + + + + + + + +
      No:Device NamePassword
      + No entries added yet . +
      + + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + +
      No:Destination
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + + + + + + + + + + + + + + + +
      No:DescriptionSearch BaseScope
      + No entries added yet . +
      + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      No:APNUsernamePasswordProxyPort
      + No entries added yet . +
      + + + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + + + + + + + + + + + + + + + + + + +
      No:APNAuth.TypeUsernamePasswordProxyPort
      + No entries added yet . +
      + + + + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + + Restrictions on Device Functionality : +
      +
      +
        +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
          +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      +
      +
      + Restrictions on Applications : +
      +
      +
        +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
          +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + + +
          +
        • +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      +
      + + + +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-windows.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-windows.hbs new file mode 100644 index 000000000..5febc3972 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/public/templates/hidden-operations-windows.hbs @@ -0,0 +1,460 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable camera. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable storage-encryption. +
      +
      +
      + +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.hbs new file mode 100644 index 000000000..223029164 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.hbs @@ -0,0 +1,87 @@ + + {{#defineZone "policy-profile-top"}} +
      +
      + +
      +
      + {{/defineZone}} + + +
      +
      +
      +
      +
      Policy Overview +
      + {{#defineZone "policy-detail-properties"}} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Platform
      Ownership
      Action upon non-compliance
      Status
      Assigned Users
      Assigned Roles
      + {{/defineZone}} +
      Description
      +
      +
      +
      +
      + +
      Profile + Information +
      +
      + +
      +
      +
      + + Loading platform features . . . +
      +
      +
      +
      +
      +
      +
      +
      +
      + +{{#zone "bottomJs"}} + + + + {{js "/js/policy-view.js"}} +{{/zone}} + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.js new file mode 100644 index 000000000..36b130ca0 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.js @@ -0,0 +1,25 @@ +/* + * 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("policy-view-edit-unit backend js"); + log.debug("calling policy-view-edit-unit"); + var userModule = require("/app/modules/user.js").userModule; + context.roles = userModule.getRoles().content; + return context; +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.json new file mode 100644 index 000000000..fd2590129 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.view/view.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/js/policy-create.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/js/policy-create.js new file mode 100644 index 000000000..a51ae295d --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/js/policy-create.js @@ -0,0 +1,2355 @@ +/* + * 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. + */ + +var validateStep = {}; +var validateInline = {}; +var stepForwardFrom = {}; +var stepBackFrom = {}; +var policy = {}; +var configuredOperations = []; + +// Constants to define platform types available +var platformTypeConstants = { + "ANDROID": "android", + "IOS": "ios", + "WINDOWS": "windows" +}; + +// Constants to define platform types ids. +var platformIds = { + "ANDROID": 1, + "IOS": 3, + "WINDOWS": 2 +}; + +// Constants to define Android Operation Constants +var androidOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION": "camera", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION": "encrypt-storage", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE", + "WIFI_OPERATION": "wifi", + "WIFI_OPERATION_CODE": "WIFI" +}; + +// Constants to define Android Operation Constants +var windowsOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "CAMERA_OPERATION": "camera", + "CAMERA_OPERATION_CODE": "CAMERA", + "ENCRYPT_STORAGE_OPERATION": "encrypt-storage", + "ENCRYPT_STORAGE_OPERATION_CODE": "ENCRYPT_STORAGE" +}; + +// Constants to define iOS Operation Constants +var iosOperationConstants = { + "PASSCODE_POLICY_OPERATION": "passcode-policy", + "PASSCODE_POLICY_OPERATION_CODE": "PASSCODE_POLICY", + "RESTRICTIONS_OPERATION": "restrictions", + "RESTRICTIONS_OPERATION_CODE": "RESTRICTION", + "WIFI_OPERATION": "wifi", + "WIFI_OPERATION_CODE": "WIFI", + "EMAIL_OPERATION": "email", + "EMAIL_OPERATION_CODE": "EMAIL", + "AIRPLAY_OPERATION": "airplay", + "AIRPLAY_OPERATION_CODE": "AIR_PLAY", + "LDAP_OPERATION": "ldap", + "LDAP_OPERATION_CODE": "LDAP", + "CALENDAR_OPERATION": "calendar", + "CALENDAR_OPERATION_CODE": "CALDAV", + "CALENDAR_SUBSCRIPTION_OPERATION": "calendar-subscription", + "CALENDAR_SUBSCRIPTION_OPERATION_CODE": "CALENDAR_SUBSCRIPTION", + "APN_OPERATION": "apn", + "APN_OPERATION_CODE": "APN", + "CELLULAR_OPERATION": "cellular", + "CELLULAR_OPERATION_CODE": "CELLULAR" +}; + +/** + * Method to update the visibility of grouped input. + * @param domElement HTML grouped-input element with class name "grouped-input" + */ +var updateGroupedInputVisibility = function (domElement) { + if ($(".parent-input:first", domElement).is(":checked")) { + if ($(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).removeClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', false); + }); + } else { + if (!$(".grouped-child-input:first", domElement).hasClass("disabled")) { + $(".grouped-child-input:first", domElement).addClass("disabled"); + } + $(".child-input", domElement).each(function () { + $(this).prop('disabled', true); + }); + } +}; + +var validateInline = {}; +var clearInline = {}; + +var enableInlineError = function (inputField, errorMsg, errorSign) { + var fieldIdentifier = "#" + inputField; + var errorMsgIdentifier = "#" + inputField + " ." + errorMsg; + var errorSignIdentifier = "#" + inputField + " ." + errorSign; + + if (inputField) { + $(fieldIdentifier).addClass(" has-error has-feedback"); + } + + if (errorMsg) { + $(errorMsgIdentifier).removeClass(" hidden"); + } + + if (errorSign) { + $(errorSignIdentifier).removeClass(" hidden"); + } +}; + +var disableInlineError = function (inputField, errorMsg, errorSign) { + var fieldIdentifier = "#" + inputField; + var errorMsgIdentifier = "#" + inputField + " ." + errorMsg; + var errorSignIdentifier = "#" + inputField + " ." + errorSign; + + if (inputField) { + $(fieldIdentifier).removeClass(" has-error has-feedback"); + } + + if (errorMsg) { + $(errorMsgIdentifier).addClass(" hidden"); + } + + if (errorSign) { + $(errorSignIdentifier).addClass(" hidden"); + } +}; + +/** + *clear inline validation messages. + */ +clearInline["policy-name"] = function () { + disableInlineError("plicynameField", "nameEmpty", "nameError"); +}; + + +/** + * Validate if provided policy name is valid against RegEx configures. + */ +validateInline["policy-name"] = function () { + var policyName = $("input#policy-name-input").val(); + if (policyName && inputIsValidAgainstLength(policyName, 1, 30)) { + disableInlineError("plicynameField", "nameEmpty", "nameError"); + } else { + enableInlineError("plicynameField", "nameEmpty", "nameError"); + } +}; + +$("#policy-name-input").focus(function () { + clearInline["policy-name"](); +}); + +$("#policy-name-input").blur(function () { + validateInline["policy-name"](); +}); + +/** + * Checks if provided number is valid against a range. + * + * @param numberInput Number Input + * @param min Minimum Limit + * @param max Maximum Limit + * @returns {boolean} Returns true if input is within the specified range + */ +var inputIsValidAgainstRange = function (numberInput, min, max) { + return (numberInput == min || (numberInput > min && numberInput < max) || numberInput == max); +}; + +/** + * Checks if provided input is valid against RegEx input. + * + * @param regExp Regular expression + * @param input Input string to check + * @returns {boolean} Returns true if input matches RegEx + */ +var inputIsValidAgainstRegExp = function (regExp, input) { + return regExp.test(input); +}; + +validateStep["policy-profile"] = function () { + var validationStatusArray = []; + var validationStatus; + var operation; + + // starting validation process and updating validationStatus + if (policy["platform"] == platformTypeConstants["ANDROID"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(androidOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = androidOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + var continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + var passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + var passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CAMERA + if ($.inArray(androidOperationConstants["CAMERA_OPERATION_CODE"], configuredOperations) != -1) { + // if CAMERA is configured + operation = androidOperationConstants["CAMERA_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating ENCRYPT_STORAGE + if ($.inArray(androidOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"], configuredOperations) != -1) { + // if ENCRYPT_STORAGE is configured + operation = androidOperationConstants["ENCRYPT_STORAGE_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating WIFI + if ($.inArray(androidOperationConstants["WIFI_OPERATION_CODE"], configuredOperations) != -1) { + // if WIFI is configured + operation = androidOperationConstants["WIFI_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var wifiSSID = $("input#wifi-ssid").val(); + if (!wifiSSID) { + validationStatus = { + "error": true, + "subErrorMsg": "WIFI SSID is not given. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + } + } + if (policy["platform"] == platformTypeConstants["WINDOWS"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = windowsOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + var continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + var passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + var passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CAMERA + if ($.inArray(windowsOperationConstants["CAMERA_OPERATION_CODE"], configuredOperations) != -1) { + // if CAMERA is configured + operation = windowsOperationConstants["CAMERA_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating ENCRYPT_STORAGE + if ($.inArray(windowsOperationConstants["ENCRYPT_STORAGE_OPERATION_CODE"], configuredOperations) != -1) { + // if ENCRYPT_STORAGE is configured + operation = windowsOperationConstants["ENCRYPT_STORAGE_OPERATION"]; + // updating validationStatus + validationStatus = { + "error": false, + "okFeature": operation + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + + } + } else if (policy["platform"] == platformTypeConstants["IOS"]) { + if (configuredOperations.length == 0) { + // updating validationStatus + validationStatus = { + "error": true, + "mainErrorMsg": "You cannot continue. Zero configured features." + }; + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } else { + // validating each and every configured Operation + // Validating PASSCODE_POLICY + if ($.inArray(iosOperationConstants["PASSCODE_POLICY_OPERATION_CODE"], configuredOperations) != -1) { + // if PASSCODE_POLICY is configured + operation = iosOperationConstants["PASSCODE_POLICY_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // validating first input: passcodePolicyMaxPasscodeAgeInDays + passcodePolicyMaxPasscodeAgeInDays = $("input#passcode-policy-max-passcode-age-in-days").val(); + if (passcodePolicyMaxPasscodeAgeInDays) { + if (!$.isNumeric(passcodePolicyMaxPasscodeAgeInDays)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyMaxPasscodeAgeInDays, 1, 730)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode age is not with in the range of 1-to-730.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // validating second and last input: passcodePolicyPasscodeHistory + if (continueToCheckNextInputs) { + passcodePolicyPasscodeHistory = $("input#passcode-policy-passcode-history").val(); + if (passcodePolicyPasscodeHistory) { + if (!$.isNumeric(passcodePolicyPasscodeHistory)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not a number.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(passcodePolicyPasscodeHistory, 1, 50)) { + validationStatus = { + "error": true, + "subErrorMsg": "Provided passcode history is not with in the range of 1-to-50.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating RESTRICTIONS + if ($.inArray(iosOperationConstants["RESTRICTIONS_OPERATION_CODE"], configuredOperations) != -1) { + // if RESTRICTION is configured + operation = iosOperationConstants["RESTRICTIONS_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // getting input values to be validated + var restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs = + "div#restrictions-autonomous-single-app-mode-permitted-app-ids .child-input"; + if ($(restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs).length > 0) { + var childInput; + var childInputArray = []; + var emptyChildInputCount = 0; + var duplicatesExist = false; + // looping through each child input + $(restrictionsAutonomousSingleAppModePermittedAppIDsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + var initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + var m, poppedChildInput; + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + var n; + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more permitted App ID entries in " + + "Autonomous Single App Mode are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with permitted App ID entries in " + + "Autonomous Single App Mode.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating WIFI + if ($.inArray(iosOperationConstants["WIFI_OPERATION_CODE"], configuredOperations) != -1) { + // if WIFI is configured + operation = iosOperationConstants["WIFI_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + // getting input values to be validated + wifiSSID = $("input#wifi-ssid").val(); + var wifiDomainName = $("input#wifi-domain-name").val(); + if (!wifiSSID && !wifiDomainName) { + validationStatus = { + "error": true, + "subErrorMsg": "Both Wi-Fi SSID and Wi-Fi Domain Name are not given. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + // getting proxy-setup value + var wifiProxyType = $("select#wifi-proxy-type").find("option:selected").attr("value"); + if (wifiProxyType == "Manual") { + // adds up additional fields to be validated + var wifiProxyServer = $("input#wifi-proxy-server").val(); + if (!wifiProxyServer) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Server is required. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var wifiProxyPort = $("input#wifi-proxy-port").val(); + if (!wifiProxyPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port is required. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(wifiProxyPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(wifiProxyPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Wi-Fi Proxy Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + } + + if (continueToCheckNextInputs) { + // getting encryption-type value + var wifiEncryptionType = $("select#wifi-encryption-type").find("option:selected").attr("value"); + if (wifiEncryptionType != "None") { + var wifiPayloadCertificateAnchorUUIDsGridChildInputs = + "div#wifi-payload-certificate-anchor-uuids .child-input"; + if ($(wifiPayloadCertificateAnchorUUIDsGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiPayloadCertificateAnchorUUIDsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Payload Certificate " + + "Anchor UUIDs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist " + + "with Payload Certificate Anchor UUIDs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var wifiTLSTrustedServerNamesGridChildInputs = + "div#wifi-tls-trusted-server-names .child-input"; + if ($(wifiTLSTrustedServerNamesGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiTLSTrustedServerNamesGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more TLS Trusted Server Names are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist " + + "with TLS Trusted Server Names.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + } + } + + if (continueToCheckNextInputs) { + var wifiRoamingConsortiumOIsGridChildInputs = "div#wifi-roaming-consortium-ois .child-input"; + if ($(wifiRoamingConsortiumOIsGridChildInputs).length > 0) { + emptyChildInputCount = 0; + var outOfAllowedLengthCount = 0; + var invalidAgainstRegExCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiRoamingConsortiumOIsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!inputIsValidAgainstLength(childInput, 6, 6) && !inputIsValidAgainstLength(childInput, 10, 10)) { + outOfAllowedLengthCount++; + } else if (!inputIsValidAgainstRegExp(/^[a-fA-F0-9]+$/, childInput)) { + invalidAgainstRegExCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (outOfAllowedLengthCount > 0) { + // if outOfMaxAllowedLength input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs " + + "are out of allowed length.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (invalidAgainstRegExCount > 0) { + // if invalid inputs in terms of hexadecimal format are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Roaming Consortium OIs " + + "contain non-hexadecimal characters.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with Roaming Consortium OIs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var wifiNAIRealmNamesGridChildInputs = "div#wifi-nai-realm-names .child-input"; + if ($(wifiNAIRealmNamesGridChildInputs).length > 0) { + emptyChildInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiNAIRealmNamesGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more NAI Realm Names are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with NAI Realm Names.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var wifiMCCAndMNCsGridChildInputs = "div#wifi-mcc-and-mncs .child-input"; + if ($(wifiMCCAndMNCsGridChildInputs).length > 0) { + var childInputCount = 0; + var stringPair; + emptyChildInputCount = 0; + outOfAllowedLengthCount = 0; + var notNumericInputCount = 0; + childInputArray = []; + duplicatesExist = false; + // looping through each child input + $(wifiMCCAndMNCsGridChildInputs).each(function () { + childInput = $(this).val(); + // pushing each string pair to childInputArray + childInputCount++; + if (childInputCount % 2 == 1) { + // initialize stringPair value + stringPair = ""; + // append first part of the string + stringPair += childInput; + } else { + // append second part of the string + stringPair += childInput; + childInputArray.push(stringPair); + } + // updating emptyChildInputCount & outOfAllowedLengthCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!$.isNumeric(childInput)) { + notNumericInputCount++; + } else if (!inputIsValidAgainstLength(childInput, 3, 3)) { + outOfAllowedLengthCount++; + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (notNumericInputCount > 0) { + // if notNumeric input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs are not numeric.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (outOfAllowedLengthCount > 0) { + // if outOfAllowedLength input is present + validationStatus = { + "error": true, + "subErrorMsg": "One or more MCC/MNC pairs " + + "do not fulfill the accepted length of 6 digits.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with MCC/MNC pairs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating EMAIL + if ($.inArray(iosOperationConstants["EMAIL_OPERATION_CODE"], configuredOperations) != -1) { + // if EMAIL is configured + operation = iosOperationConstants["EMAIL_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var emailAddress = $("input#email-address").val(); + if (emailAddress && !inputIsValidAgainstRegExp(/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/, emailAddress)) { + validationStatus = { + "error": true, + "subErrorMsg": "Email Address is not valid.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var emailIncomingMailServerHostname = $("input#email-incoming-mail-server-hostname").val(); + if (!emailIncomingMailServerHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Hostname is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailIncomingMailServerPort = $("input#email-incoming-mail-server-port").val(); + if (emailIncomingMailServerPort && emailIncomingMailServerPort != '') { + if (!$.isNumeric(emailIncomingMailServerPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(emailIncomingMailServerPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Incoming Mail Server Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + var emailOutgoingMailServerHostname = $("input#email-outgoing-mail-server-hostname").val(); + if (!emailOutgoingMailServerHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Hostname is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + if (continueToCheckNextInputs) { + var emailOutgoingMailServerPort = $("input#email-outgoing-mail-server-port").val(); + if (emailOutgoingMailServerPort) { + if (!$.isNumeric(emailOutgoingMailServerPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(emailOutgoingMailServerPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Outgoing Mail Server Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating AIRPLAY + if ($.inArray(iosOperationConstants["AIRPLAY_OPERATION_CODE"], configuredOperations) != -1) { + // if AIRPLAY is configured + operation = iosOperationConstants["AIRPLAY_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var airplayCredentialsGridChildInputs = "div#airplay-credentials .child-input"; + var airplayDestinationsGridChildInputs = "div#airplay-destinations .child-input"; + if ($(airplayCredentialsGridChildInputs).length == 0 && + $(airplayDestinationsGridChildInputs).length == 0) { + validationStatus = { + "error": true, + "subErrorMsg": "AirPlay settings have zero configurations attached.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + if ($(airplayCredentialsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(airplayCredentialsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 2 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Device Names of " + + "AirPlay Credentials are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "Device Names of AirPlay Credentials.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + if (continueToCheckNextInputs) { + if ($(airplayDestinationsGridChildInputs).length > 0) { + childInputArray = []; + emptyChildInputCount = 0; + invalidAgainstRegExCount = 0; + duplicatesExist = false; + // looping through each child input + $(airplayDestinationsGridChildInputs).each(function () { + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } else if (!inputIsValidAgainstRegExp( + /([a-z|A-Z|0-9][a-z|A-Z|0-9][:]){5}([a-z|A-Z|0-9][a-z|A-Z|0-9])$/, childInput)) { + // if child input field is invalid against RegEx + invalidAgainstRegExCount++ + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more AirPlay Destination fields are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (invalidAgainstRegExCount > 0) { + // if invalidAgainstRegEx inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more AirPlay Destination fields " + + "do not fulfill expected format.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with AirPlay Destinations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating LDAP + if ($.inArray(iosOperationConstants["LDAP_OPERATION_CODE"], configuredOperations) != -1) { + // if LDAP is configured + operation = iosOperationConstants["LDAP_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var ldapAccountHostname = $("input#ldap-account-hostname").val(); + if (!ldapAccountHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "LDAP Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var ldapSearchSettingsGridChildInputs = "div#ldap-search-settings .child-input"; + if ($(ldapSearchSettingsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(ldapSearchSettingsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 3 == 2) { + // if child input is of second column + childInput = $(this).find("option:selected").attr("value"); + stringPair = ""; + stringPair += (childInput + " "); + } else if (childInputCount % 3 == 0) { + // if child input is of third column + childInput = $(this).val(); + stringPair += childInput; + childInputArray.push(stringPair); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more Search Setting Scope fields are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "Search Setting Search Base and Scope pairs.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CALENDAR + if ($.inArray(iosOperationConstants["CALENDAR_OPERATION_CODE"], configuredOperations) != -1) { + // if CALENDAR is configured + operation = iosOperationConstants["CALENDAR_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var calendarAccountHostname = $("input#calendar-account-hostname").val(); + if (!calendarAccountHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var calendarAccountPort = $("input#calendar-account-port").val(); + if (!calendarAccountPort) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!$.isNumeric(calendarAccountPort)) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port requires a number input.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (!inputIsValidAgainstRange(calendarAccountPort, 0, 65535)) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Port is not within the range " + + "of valid port numbers.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CALENDAR_SUBSCRIPTION + if ($.inArray(iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION_CODE"], configuredOperations) != -1) { + // if CALENDAR_SUBSCRIPTION is configured + operation = iosOperationConstants["CALENDAR_SUBSCRIPTION_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var calendarSubscriptionHostname = $("input#calendar-subscription-hostname").val(); + if (!calendarSubscriptionHostname) { + validationStatus = { + "error": true, + "subErrorMsg": "Account Hostname URL is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating APN + if ($.inArray(iosOperationConstants["APN_OPERATION_CODE"], configuredOperations) != -1) { + // if APN is configured + operation = iosOperationConstants["APN_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var apnConfigurationsGridChildInputs = "div#apn-configurations .child-input"; + if ($(apnConfigurationsGridChildInputs).length == 0) { + validationStatus = { + "error": true, + "subErrorMsg": "APN Settings have zero configurations attached.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if ($(apnConfigurationsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + // checking empty APN field count + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(apnConfigurationsGridChildInputs).each(function () { + childInputCount++; + //if (childInputCount % 5 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + //} + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more APN fields of Configurations are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "APN fields of Configurations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + // Validating CELLULAR + if ($.inArray(iosOperationConstants["CELLULAR_OPERATION_CODE"], configuredOperations) != -1) { + // if CELLULAR is configured + operation = iosOperationConstants["CELLULAR_OPERATION"]; + // initializing continueToCheckNextInputs to true + continueToCheckNextInputs = true; + + var cellularAttachAPNName = $("input#cellular-attach-apn-name").val(); + if (!cellularAttachAPNName) { + validationStatus = { + "error": true, + "subErrorMsg": "Cellular Configuration Name is empty. You cannot proceed.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + + if (continueToCheckNextInputs) { + var cellularAPNConfigurationsGridChildInputs = "div#cellular-apn-configurations .child-input"; + if ($(cellularAPNConfigurationsGridChildInputs).length > 0) { + childInputCount = 0; + childInputArray = []; + // checking empty APN field count + emptyChildInputCount = 0; + duplicatesExist = false; + // looping through each child input + $(cellularAPNConfigurationsGridChildInputs).each(function () { + childInputCount++; + if (childInputCount % 6 == 1) { + // if child input is of first column + childInput = $(this).val(); + childInputArray.push(childInput); + // updating emptyChildInputCount + if (!childInput) { + // if child input field is empty + emptyChildInputCount++; + } + } + }); + // checking for duplicates + initialChildInputArrayLength = childInputArray.length; + if (emptyChildInputCount == 0 && initialChildInputArrayLength > 1) { + for (m = 0; m < (initialChildInputArrayLength - 1); m++) { + poppedChildInput = childInputArray.pop(); + for (n = 0; n < childInputArray.length; n++) { + if (poppedChildInput == childInputArray[n]) { + duplicatesExist = true; + break; + } + } + if (duplicatesExist) { + break; + } + } + } + // updating validationStatus + if (emptyChildInputCount > 0) { + // if empty child inputs are present + validationStatus = { + "error": true, + "subErrorMsg": "One or more APN fields of APN Configurations are empty.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } else if (duplicatesExist) { + // if duplicate input is present + validationStatus = { + "error": true, + "subErrorMsg": "Duplicate values exist with " + + "APN fields of APN Configurations.", + "erroneousFeature": operation + }; + continueToCheckNextInputs = false; + } + } + } + + // at-last, if the value of continueToCheckNextInputs is still true + // this means that no error is found + if (continueToCheckNextInputs) { + validationStatus = { + "error": false, + "okFeature": operation + }; + } + + // updating validationStatusArray with validationStatus + validationStatusArray.push(validationStatus); + } + } + } + // ending validation process + + // start taking specific notifying actions upon validation + var wizardIsToBeContinued; + var errorCount = 0; + var mainErrorMsgWrapper, mainErrorMsg, + subErrorMsgWrapper, subErrorMsg, subErrorIcon, subOkIcon, featureConfiguredIcon; + var i; + for (i = 0; i < validationStatusArray.length; i++) { + validationStatus = validationStatusArray[i]; + if (validationStatus["error"]) { + errorCount++; + if (validationStatus["mainErrorMsg"]) { + mainErrorMsgWrapper = "#policy-profile-main-error-msg"; + mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else if (validationStatus["subErrorMsg"]) { + subErrorMsgWrapper = "#" + validationStatus["erroneousFeature"] + "-feature-error-msg"; + subErrorMsg = subErrorMsgWrapper + " span"; + subErrorIcon = "#" + validationStatus["erroneousFeature"] + "-error"; + subOkIcon = "#" + validationStatus["erroneousFeature"] + "-ok"; + featureConfiguredIcon = "#" + validationStatus["erroneousFeature"] + "-configured"; + // hiding featureConfiguredState as the first step + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // updating error state and corresponding messages + $(subErrorMsg).text(validationStatus["subErrorMsg"]); + if ($(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).removeClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if ($(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).removeClass("hidden"); + } + } + } else { + if (validationStatus["okFeature"]) { + subErrorMsgWrapper = "#" + validationStatus["okFeature"] + "-feature-error-msg"; + subErrorIcon = "#" + validationStatus["okFeature"] + "-error"; + subOkIcon = "#" + validationStatus["okFeature"] + "-ok"; + featureConfiguredIcon = "#" + validationStatus["okFeature"] + "-configured"; + // hiding featureConfiguredState as the first step + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // updating success state and corresponding messages + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if ($(subOkIcon).hasClass("hidden")) { + $(subOkIcon).removeClass("hidden"); + } + } + } + } + + wizardIsToBeContinued = (errorCount == 0); + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-profile"] = function () { + policy["profile"] = operationModule.generateProfile(policy["platform"], configuredOperations); + // updating next-page wizard title with selected platform + $("#policy-criteria-page-wizard-title").text("ADD " + policy["platform"] + " POLICY"); + // updating ownership type options according to platform + if (policy["platform"] == platformTypeConstants["IOS"] || + policy["platform"] == platformTypeConstants["WINDOWS"]) { + var ownershipTypeSelectOptions = $("#ownership-input"); + ownershipTypeSelectOptions.empty(); + ownershipTypeSelectOptions.append($(""). + attr("value", "BYOD").text("BYOD (Bring Your Own Device)")); + ownershipTypeSelectOptions.attr("disabled", true); + } +}; + +stepBackFrom["policy-profile"] = function () { + // reinitialize configuredOperations + configuredOperations = []; + // clearing already-loaded platform specific hidden-operations html content from the relevant div + // so that, the wrong content would not be shown at the first glance, in case + // the user selects a different platform + $(".wr-advance-operations").html( + "
      " + + "
      " + + "" + + "Loading Platform Features . . ." + + "
      " + + "
      " + + "
      " + ); +}; + +stepForwardFrom["policy-criteria"] = function () { + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(':radio')) { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + policy["selectedUsers"] = $("#users-input").val(); + } else if ($(this).attr("id") == "user-roles-radio-btn") { + policy["selectedUserRoles"] = $("#user-roles-input").val(); + } + } + } + }); + policy["selectedNonCompliantAction"] = $("#action-input").find(":selected").data("action"); + policy["selectedOwnership"] = $("#ownership-input").val(); + //updating next-page wizard title with selected platform + $("#policy-naming-page-wizard-title").text("ADD " + policy["platform"] + " POLICY"); +}; + +/** + * Checks if provided input is valid against provided length range. + * + * @param input Alphanumeric or non-alphanumeric input + * @param minLength Minimum Required Length + * @param maxLength Maximum Required Length + * @returns {boolean} Returns true if input matches the provided minimum length and maximum length + */ +var inputIsValidAgainstLength = function (input, minLength, maxLength) { + var length = input.length; + return (length == minLength || (length > minLength && length < maxLength) || length == maxLength); +}; + +validateStep["policy-criteria"] = function () { + var validationStatus = {}; + var selectedAssignees; + var selectedField = "Role(s)"; + + $("input[type='radio'].select-users-radio").each(function () { + if ($(this).is(":checked")) { + if ($(this).attr("id") == "users-radio-btn") { + selectedAssignees = $("#users-input").val(); + selectedField = "User(s)"; + } else if ($(this).attr("id") == "user-roles-radio-btn") { + selectedAssignees = $("#user-roles-input").val(); + } + return false; + } + }); + + if (selectedAssignees) { + validationStatus["error"] = false; + } else { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = selectedField + " is a required field. It cannot be empty"; + } + + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-criteria-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-naming"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +validateStep["policy-platform"] = function () { + return false; +}; + +validateStep["policy-naming-publish"] = function () { + var validationStatus = {}; + + // taking values of inputs to be validated + var policyName = $("input#policy-name-input").val(); + // starting validation process and updating validationStatus + if (!policyName) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = "Policy name is empty. You cannot proceed."; + } else if (!inputIsValidAgainstLength(policyName, 1, 30)) { + validationStatus["error"] = true; + validationStatus["mainErrorMsg"] = + "Policy name exceeds maximum allowed length."; + } else { + validationStatus["error"] = false; + } + // ending validation process + + // start taking specific actions upon validation + var wizardIsToBeContinued; + if (validationStatus["error"]) { + wizardIsToBeContinued = false; + var mainErrorMsgWrapper = "#policy-naming-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(validationStatus["mainErrorMsg"]); + $(mainErrorMsgWrapper).removeClass("hidden"); + } else { + wizardIsToBeContinued = true; + } + + return wizardIsToBeContinued; +}; + +stepForwardFrom["policy-naming-publish"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + savePolicy(policy, "/devicemgt_admin/policies/active-policy"); +}; +stepForwardFrom["policy-naming"] = function () { + policy["policyName"] = $("#policy-name-input").val(); + policy["description"] = $("#policy-description-input").val(); + //All data is collected. Policy can now be updated. + savePolicy(policy, "/devicemgt_admin/policies/inactive-policy"); +}; + +var savePolicy = function (policy, serviceURL) { + var profilePayloads = []; + // traverses key by key in policy["profile"] + var key; + for (key in policy["profile"]) { + if (policy["platformId"] == platformIds["WINDOWS"] && + key == windowsOperationConstants["PASSCODE_POLICY_OPERATION_CODE"]) { + policy["profile"][key].enablePassword = true; + } + if (policy["profile"].hasOwnProperty(key)) { + profilePayloads.push({ + "featureCode": key, + "deviceTypeId": policy["platformId"], + "content": policy["profile"][key] + }); + } + } + + $.each(profilePayloads, function (i, item) { + $.each(item.content, function (key, value) { + if (!value) { + item.content[key] = null; + } + }); + }); + + var payload = { + "policyName": policy["policyName"], + "description": policy["description"], + "compliance": policy["selectedNonCompliantAction"], + "ownershipType": policy["selectedOwnership"], + "profile": { + "profileName": policy["policyName"], + "deviceType": { + "id": policy["platformId"] + }, + "profileFeaturesList": profilePayloads + } + }; + + if (policy["selectedUsers"]) { + payload["users"] = policy["selectedUsers"]; + } else if (policy["selectedUserRoles"]) { + payload["roles"] = policy["selectedUserRoles"]; + } else { + payload["users"] = []; + payload["roles"] = []; + } + + invokerUtil.post( + serviceURL, + payload, + function () { + $(".add-policy").addClass("hidden"); + $(".policy-naming").addClass("hidden"); + $(".policy-message").removeClass("hidden"); + }, + function (data) { + } + ); +}; + +// Start of HTML embedded invoke methods +var showAdvanceOperation = function (operation, button) { + $(button).addClass('selected'); + $(button).siblings().removeClass('selected'); + var hiddenOperation = ".wr-hidden-operations-content > div"; + $(hiddenOperation + '[data-operation="' + operation + '"]').show(); + $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide(); +}; + +/** + * Method to slide down a provided pane upon provided value set. + * + * @param selectElement Select HTML Element to consider + * @param paneID HTML ID of div element to slide down + * @param valueSet Applicable Value Set + */ +var slideDownPaneAgainstValueSet = function (selectElement, paneID, valueSet) { + var selectedValueOnChange = $(selectElement).find("option:selected").val(); + var i, slideDownVotes = 0; + for (i = 0; i < valueSet.length; i++) { + if (selectedValueOnChange == valueSet[i]) { + slideDownVotes++; + } + } + var paneSelector = "#" + paneID; + if (slideDownVotes > 0) { + if (!$(paneSelector).hasClass("expanded")) { + $(paneSelector).addClass("expanded"); + } + $(paneSelector).slideDown(); + } else { + if ($(paneSelector).hasClass("expanded")) { + $(paneSelector).removeClass("expanded"); + } + $(paneSelector).slideUp(); + /** now follows the code to reinitialize all inputs of the slidable pane */ + // reinitializing input fields into the defaults + $(paneSelector + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(paneSelector + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(paneSelector + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(paneSelector + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } +}; +// End of HTML embedded invoke methods + + +// Start of functions related to grid-input-view + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var setId = function (addFormContainer) { + $(addFormContainer).find("[data-add-form-clone]").each(function (i) { + $(this).attr("id", $(this).attr("data-add-form-clone").slice(1) + "-" + (i + 1)); + if ($(this).find(".index").length > 0) { + $(this).find(".index").html(i + 1); + } + }); +}; + +/** + * Method to set count id to cloned elements. + * @param {object} addFormContainer + */ +var showHideHelpText = function (addFormContainer) { + var helpText = "[data-help-text=add-form]"; + if ($(addFormContainer).find("[data-add-form-clone]").length > 0) { + $(addFormContainer).find(helpText).hide(); + } else { + $(addFormContainer).find(helpText).show(); + } +}; + +function formatRepo(user) { + if (user.loading) { + return user.text; + } + if (!user.username) { + return; + } + var markup = '
      ' + + '
      ' + + '
      ' + + '
      ' + user.username + '
      '; + if (user.firstname) { + markup += '
      ' + user.firstname + '
      '; + } + if (user.emailAddress) { + markup += '
      ' + user.emailAddress + '
      '; + } + markup += '
      '; + return markup; +} + +function formatRepoSelection(user) { + return user.username || user.text; +} + +function promptErrorPolicyPlatform(errorMsg) { + var mainErrorMsgWrapper = "#policy-platform-main-error-msg"; + var mainErrorMsg = mainErrorMsgWrapper + " span"; + $(mainErrorMsg).text(errorMsg); + $(mainErrorMsgWrapper).removeClass("hidden"); +} + +// End of functions related to grid-input-view + + +$(document).ready(function () { + $("#users-input").select2({ + multiple: true, + tags: false, + ajax: { + url: window.location.origin + "/devicemgt/api/invoker/execute/", + method: "POST", + dataType: 'json', + delay: 250, + id: function (user) { + return user.username; + }, + data: function (params) { + var postData = {}; + postData.actionMethod = "GET"; + postData.actionUrl = "/devicemgt_admin/users"; + postData.actionPayload = JSON.stringify({ + q: params.term, // search term + page: params.page + }); + + return JSON.stringify(postData); + }, + processResults: function (data, page) { + var newData = []; + $.each(data.responseContent, function (index, value) { + value.id = value.username; + newData.push(value); + }); + return { + results: newData + }; + }, + cache: true + }, + escapeMarkup: function (markup) { + return markup; + }, // let our custom formatter work + minimumInputLength: 1, + templateResult: formatRepo, // omitted for brevity, see the source of this page + templateSelection: formatRepoSelection // omitted for brevity, see the source of this page + }); + + $("#loading-content").remove(); + $(".policy-platform").removeClass("hidden"); + // Adding initial state of wizard-steps. + $("#policy-profile-wizard-steps").html($(".wr-steps").html()); + + policy["platform"] = $("#platform").data("platform"); + policy["platformId"] = $("#platform").data("platform-id"); + // updating next-page wizard title with selected platform + $("#policy-profile-page-wizard-title").text("ADD " + policy["platform"] + " POLICY"); + + var deviceType = policy["platform"]; + var hiddenOperationsByDeviceType = $("#hidden-operations-" + deviceType); + var hiddenOperationsByDeviceTypeCacheKey = deviceType + "HiddenOperations"; + var hiddenOperationsByDeviceTypeSrc = hiddenOperationsByDeviceType.attr("src"); + + setTimeout( + function () { + $.template(hiddenOperationsByDeviceTypeCacheKey, hiddenOperationsByDeviceTypeSrc, function (template) { + var content = template(); + $(".wr-advance-operations").html(content); + $(".wr-advance-operations li.grouped-input").each(function () { + updateGroupedInputVisibility(this); + }); + }); + }, + 250 // time delayed for the execution of above function, 250 milliseconds + ); + + $("select.select2[multiple=multiple]").select2({ + "tags": false + }); + + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + + $("input[type='radio'].select-users-radio").change(function () { + if ($("#users-radio-btn").is(":checked")) { + $("#user-roles-select-field").hide(); + $("#users-select-field").show(); + } + if ($("#user-roles-radio-btn").is(":checked")) { + $("#users-select-field").hide(); + $("#user-roles-select-field").show(); + } + }); + + // Support for special input type "ANY" on user(s) & user-role(s) selection + $("#user-roles-input").select2({ + "tags": false + }).on("select2:select", function (e) { + if (e.params.data.id == "ANY") { + $(this).val("ANY").trigger("change"); + } else { + $("option[value=ANY]", this).prop("selected", false).parent().trigger("change"); + } + }); + + // Maintains an array of configured features of the profile + var advanceOperations = ".wr-advance-operations"; + $(advanceOperations).on("click", ".wr-input-control.switch", function (event) { + var operationCode = $(this).parents(".operation-data").data("operation-code"); + var operation = $(this).parents(".operation-data").data("operation"); + var operationDataWrapper = $(this).data("target"); + // prevents event bubbling by figuring out what element it's being called from. + if (event.target.tagName == "INPUT") { + var featureConfiguredIcon; + if ($("input[type='checkbox']", this).is(":checked")) { + configuredOperations.push(operationCode); + // when a feature is enabled, if "zero-configured-features" msg is available, hide that. + var zeroConfiguredOperationsErrorMsg = "#policy-profile-main-error-msg"; + if (!$(zeroConfiguredOperationsErrorMsg).hasClass("hidden")) { + $(zeroConfiguredOperationsErrorMsg).addClass("hidden"); + } + // add configured-state-icon to the feature + featureConfiguredIcon = "#" + operation + "-configured"; + if ($(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).removeClass("hidden"); + } + } else { + //splicing the array if operation is present. + var index = $.inArray(operationCode, configuredOperations); + if (index != -1) { + configuredOperations.splice(index, 1); + } + // when a feature is disabled, clearing all its current configured, error or success states + var subErrorMsgWrapper = "#" + operation + "-feature-error-msg"; + var subErrorIcon = "#" + operation + "-error"; + var subOkIcon = "#" + operation + "-ok"; + featureConfiguredIcon = "#" + operation + "-configured"; + + if (!$(subErrorMsgWrapper).hasClass("hidden")) { + $(subErrorMsgWrapper).addClass("hidden"); + } + if (!$(subErrorIcon).hasClass("hidden")) { + $(subErrorIcon).addClass("hidden"); + } + if (!$(subOkIcon).hasClass("hidden")) { + $(subOkIcon).addClass("hidden"); + } + if (!$(featureConfiguredIcon).hasClass("hidden")) { + $(featureConfiguredIcon).addClass("hidden"); + } + // reinitializing input fields into the defaults + $(operationDataWrapper + " input").each( + function () { + if ($(this).is("input:text")) { + $(this).val($(this).data("default")); + } else if ($(this).is("input:password")) { + $(this).val(""); + } else if ($(this).is("input:checkbox")) { + $(this).prop("checked", $(this).data("default")); + // if this checkbox is the parent input of a grouped-input + if ($(this).hasClass("parent-input")) { + var groupedInput = $(this).parent().parent().parent(); + updateGroupedInputVisibility(groupedInput); + } + } + } + ); + // reinitializing select fields into the defaults + $(operationDataWrapper + " select").each( + function () { + var defaultOption = $(this).data("default"); + $("option:eq(" + defaultOption + ")", this).prop("selected", "selected"); + } + ); + // collapsing expanded-panes (upon the selection of html-select-options) if any + $(operationDataWrapper + " .expanded").each( + function () { + if ($(this).hasClass("expanded")) { + $(this).removeClass("expanded"); + } + $(this).slideUp(); + } + ); + // removing all entries of grid-input elements if exist + $(operationDataWrapper + " .grouped-array-input").each( + function () { + var gridInputs = $(this).find("[data-add-form-clone]"); + if (gridInputs.length > 0) { + gridInputs.remove(); + } + var helpTexts = $(this).find("[data-help-text=add-form]"); + if (helpTexts.length > 0) { + helpTexts.show(); + } + } + ); + } + } + }); + + // adding support for cloning multiple profiles per feature with cloneable class definitions + $(advanceOperations).on("click", ".multi-view.add.enabled", function () { + // get a copy of .cloneable and create new .cloned div element + var cloned = "

      " + $(".cloneable", $(this).parent().parent()).html() + "
      "; + // append newly created .cloned div element to panel-body + $(this).parent().parent().append(cloned); + // enable remove action of newly cloned div element + $(".cloned", $(this).parent().parent()).each( + function () { + if ($(".multi-view.remove", this).hasClass("disabled")) { + $(".multi-view.remove", this).removeClass("disabled"); + } + if (!$(".multi-view.remove", this).hasClass("enabled")) { + $(".multi-view.remove", this).addClass("enabled"); + } + } + ); + }); + + $(advanceOperations).on("click", ".multi-view.remove.enabled", function () { + $(this).parent().remove(); + }); + + // enabling or disabling grouped-input based on the status of a parent check-box + $(advanceOperations).on("click", ".grouped-input", function () { + updateGroupedInputVisibility(this); + }); + + // add form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=add-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + var clonedForm = $("[data-add-form=" + $(this).attr("href") + "]").clone(). + find("[data-add-form-element=clone]").attr("data-add-form-clone", $(this).attr("href")); + + // adding class .child-input to capture text-input-array-values + $("input, select", clonedForm).addClass("child-input"); + + $(addFormContainer).append(clonedForm); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + // remove form entry click function for grid inputs + $(advanceOperations).on("click", "[data-click-event=remove-form]", function () { + var addFormContainer = $("[data-add-form-container=" + $(this).attr("href") + "]"); + + $(this).closest("[data-add-form-element=clone]").remove(); + setId(addFormContainer); + showHideHelpText(addFormContainer); + }); + + $(".wizard-stepper").click(function () { + // button clicked here can be either a continue button or a back button. + var currentStep = $(this).data("current"); + var validationIsRequired = $(this).data("validate"); + var wizardIsToBeContinued; + + if (validationIsRequired) { + wizardIsToBeContinued = validateStep[currentStep](); + } else { + wizardIsToBeContinued = true; + } + + if (wizardIsToBeContinued) { + // When moving back and forth, following code segment will + // remove if there are any visible error-messages. + var errorMsgWrappers = ".alert.alert-danger"; + $(errorMsgWrappers).each( + function () { + if (!$(this).hasClass("hidden")) { + $(this).addClass("hidden"); + } + } + ); + + var nextStep = $(this).data("next"); + var isBackBtn = $(this).data("is-back-btn"); + + // if current button is a continuation... + if (!isBackBtn) { + // initiate stepForwardFrom[*] functions to gather form data. + if (stepForwardFrom[currentStep]) { + stepForwardFrom[currentStep](this); + } + } else { + // initiate stepBackFrom[*] functions to rollback. + if (stepBackFrom[currentStep]) { + stepBackFrom[currentStep](); + } + } + + // following step occurs only at the last stage of the wizard. + if (!nextStep) { + window.location.href = $(this).data("direct"); + } + + // updating next wizard step as current. + $(".itm-wiz").each(function () { + var step = $(this).data("step"); + if (step == nextStep) { + $(this).addClass("itm-wiz-current"); + } else { + $(this).removeClass("itm-wiz-current"); + } + }); + + // adding next update of wizard-steps. + $("#" + nextStep + "-wizard-steps").html($(".wr-steps").html()); + + // hiding current section of the wizard and showing next section. + $("." + currentStep).addClass("hidden"); + $("." + nextStep).removeClass("hidden"); + } + }); +}); \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-android.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-android.hbs new file mode 100644 index 000000000..094f7f73f --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-android.hbs @@ -0,0 +1,458 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable camera. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you do not need the device to be encrypted. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + + + + + + + + + + + + + + + + Please note that * sign represents required fields of data. +
      +
      + +
      + + + +
      +
      + + +
      + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-ios.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-ios.hbs new file mode 100644 index 000000000..113ce1370 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-ios.hbs @@ -0,0 +1,2923 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + + + +
      + + +
      + + + +
      + +
      + + + + + + + + + + + + + +
      No:Roaming Consortium OI
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + +
      No:NAI Realm Name
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + + +
      No:Mobile Country Code ( MCC )Mobile Network Code ( MNC )
      + No entries added yet . +
      + + + + + + + + + + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + +
      + +
      + Incoming Mail Settings : +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + Outgoing Mail Settings : +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + +
      + + + + + + + + + + + + + + +
      No:Device NamePassword
      + No entries added yet . +
      + + + + + + + + + + +
      +
      + +
      + +
      + +
      + + + + + + + + + + + + + +
      No:Destination
      + No entries added yet . +
      + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + + + + + + + + + + + + + + + +
      No:DescriptionSearch BaseScope
      + No entries added yet . +
      + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      No:APNUsernamePasswordProxyPort
      + No entries added yet . +
      + + + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      + + + + + + + + + + + + + + + + + + +
      No:APNAuth.TypeUsernamePasswordProxyPort
      + No entries added yet . +
      + + + + + + + + + + + + + + +
      +
      + +
      +
      +
      + + + +
      +
      + +
      + + + + Restrictions on Device Functionality : +
      +
      +
        +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
          +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      +
      +
      + Restrictions on Applications : +
      +
      +
        +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
          +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + +
          +
        • +
        • +
          + + +
          +
        • +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      • +
        + +
        +
      • +
      +
      + + + +
      +
      +
      + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-windows.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-windows.hbs new file mode 100644 index 000000000..3b5bb3bef --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/public/templates/hidden-operations-windows.hbs @@ -0,0 +1,460 @@ +
      + + +
      + +
      +
      + +
      + + + +
      + +
      + +
      + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      + +
      + + +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable camera. +
      +
      +
      + +
      +
      +
      +
      +
      + + + +
      +
      + +
      + + Un-check following checkbox in case you need to disable storage-encryption. +
      +
      +
      + +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.hbs new file mode 100644 index 000000000..08e9ca77d --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.hbs @@ -0,0 +1,278 @@ + +
      +
      + + + + + + +
      + + + +
      +
      +

      ADD POLICY

      +
      +
      +
      +
      +
      +

      Step 2: Configure profile

      +
      + + +
      +
      +
      +       + +     + Loading platform features . . . +
      +
      +
      +
      + +
      +
      +
      +
      + + +
      + +{{#zone "bottomJs"}} + + + + {{js "js/policy-create.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.js b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.js new file mode 100644 index 000000000..2a2200640 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.js @@ -0,0 +1,37 @@ +/* + * 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 userModule = require("/app/modules/user.js")["userModule"]; + var utility = require('/app/modules/utility.js').utility; + var response = userModule.getRoles(); + var wizardPage = {}; + if (response["status"] == "success") { + wizardPage["roles"] = response["content"]; + } + var deviceType = context.uriParams.deviceType; + var typesListResponse = userModule.getPlatforms(); + if (typesListResponse["status"] == "success") { + for (var type in typesListResponse["content"]) { + if (deviceType == typesListResponse["content"][type]["name"]) { + wizardPage["type"] = typesListResponse["content"][type]; + } + } + } + return wizardPage; +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.json new file mode 100644 index 000000000..fd2590129 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.policy.wizard/wizard.json @@ -0,0 +1,3 @@ +{ + "version" : "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.hbs b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.hbs new file mode 100644 index 000000000..7e30c1cb7 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.hbs @@ -0,0 +1 @@ +{{#zone "productName"}}ENTERPRISE MOBILITY MANAGER{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.json b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.json new file mode 100644 index 000000000..1299a7b1b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.ui.header.logo/logo.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "index": 30, + "extends": "cdmf.unit.ui.header.logo" +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml new file mode 100644 index 000000000..bbb1c990a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml @@ -0,0 +1,81 @@ + + + + + mobile-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.url.printer + bundle + WSO2 Carbon - Startup Handler That Prints MDM End-User Web-App URL + WSO2 Carbon - Startup Handler That Prints MDM End-User Web-App URL + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + Bundle Containing The Startup Handler That Prints MDM End-User Web-App URL + org.wso2.carbon.device.mgt.mobile.url.printer.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + org.apache.axis2.*;version="${axis2.osgi.version.range}", + org.wso2.carbon.core, + org.wso2.carbon.utils.*, + + + !org.wso2.carbon.device.mgt.mobile.url.printer.internal, + org.wso2.carbon.device.mgt.mobile.url.printer, + + + + + + + + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.carbon + org.wso2.carbon.core + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.apache.axis2.wso2 + axis2 + + + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java new file mode 100644 index 000000000..1eaad8ad4 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.url.printer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.core.ServerStartupObserver; +import org.wso2.carbon.device.mgt.mobile.url.printer.internal.URLPrinterDataHolder; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.ConfigurationContextService; +import org.wso2.carbon.utils.NetworkUtils; + +public class URLPrinterStartupHandler implements ServerStartupObserver { + + private static final Log log = LogFactory.getLog(URLPrinterStartupHandler.class); + + @Override + public void completingServerStartup() { + + } + + @Override + public void completedServerStartup() { + log.info("Device Management Console URL : " + this.getEmmUrl()); + } + + private String getEmmUrl() { + // Hostname + String hostName = "localhost"; + try { + hostName = NetworkUtils.getMgtHostName(); + } catch (Exception ignored) { + } + // HTTPS port + String mgtConsoleTransport = CarbonUtils.getManagementTransport(); + ConfigurationContextService configContextService = + URLPrinterDataHolder.getInstance().getConfigurationContextService(); + int port = CarbonUtils.getTransportPort(configContextService, mgtConsoleTransport); + int httpsProxyPort = + CarbonUtils.getTransportProxyPort(configContextService.getServerConfigContext(), + mgtConsoleTransport); + if (httpsProxyPort > 0) { + port = httpsProxyPort; + } + return "https://" + hostName + ":" + port + "/devicemgt"; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java new file mode 100644 index 000000000..0dd8a459d --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.url.printer.internal; + +import org.wso2.carbon.utils.ConfigurationContextService; + +public class URLPrinterDataHolder { + + private ConfigurationContextService configurationContextService; + private static URLPrinterDataHolder thisInstance = new URLPrinterDataHolder(); + + private URLPrinterDataHolder() {} + + public static URLPrinterDataHolder getInstance() { + return thisInstance; + } + + public ConfigurationContextService getConfigurationContextService() { + return configurationContextService; + } + + public void setConfigurationContextService(ConfigurationContextService configurationContextService) { + this.configurationContextService = configurationContextService; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java new file mode 100644 index 000000000..88a2b2dae --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.url.printer.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.core.ServerStartupObserver; +import org.wso2.carbon.device.mgt.mobile.url.printer.URLPrinterStartupHandler; +import org.wso2.carbon.utils.ConfigurationContextService; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.mobile.url.printer.URLPrinterStartupHandlerServiceComponent" + * immediate="true" + * @scr.reference name="config.context.service" + * interface="org.wso2.carbon.utils.ConfigurationContextService" + * cardinality="0..1" + * policy="dynamic" + * bind="setConfigurationContextService" + * unbind="unsetConfigurationContextService" + */ +public class URLPrinterStartupHandlerServiceComponent { + + private static final Log log = LogFactory.getLog(URLPrinterStartupHandlerServiceComponent.class); + + @SuppressWarnings("unused") + protected void activate(ComponentContext componentContext) { + try { + BundleContext bundleContext = componentContext.getBundleContext(); + /* Registering URL printer start-up handler */ + bundleContext.registerService(ServerStartupObserver.class, new URLPrinterStartupHandler(), null); + } catch (Throwable e) { + log.error("Error occurred while activating URL printer server start-up handler service component", e); + } + } + + @SuppressWarnings("unused") + protected void deactivate(ComponentContext componentContext) { + //do nothing + } + + protected void setConfigurationContextService(ConfigurationContextService configurationContextService) { + if (log.isDebugEnabled()) { + log.debug("Setting ConfigurationContextService"); + } + URLPrinterDataHolder.getInstance().setConfigurationContextService(configurationContextService); + } + + protected void unsetConfigurationContextService(ConfigurationContextService configurationContextService) { + if (log.isDebugEnabled()) { + log.debug("Un-setting ConfigurationContextService"); + } + URLPrinterDataHolder.getInstance().setConfigurationContextService(null); + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/pom.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/pom.xml new file mode 100644 index 000000000..73777a2da --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/pom.xml @@ -0,0 +1,172 @@ + + + + + + + mobile-base-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile + bundle + WSO2 Carbon - Mobile Device Management Impl + WSO2 Carbon - Mobile Device Management Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + Device Management Mobile Impl Bundle + org.wso2.carbon.device.mgt.mobile.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*, + javax.naming, + javax.sql, + javax.xml.parsers, + org.w3c.dom, + org.wso2.carbon.context, + org.wso2.carbon.utils.*, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.policy.mgt.common.*, + org.wso2.carbon.registry.core, + org.wso2.carbon.registry.core.service, + org.wso2.carbon.registry.core.session, + org.wso2.carbon.registry.api, + org.wso2.carbon.device.mgt.extensions.license.mgt.registry, + com.google.gson.* + + + !org.wso2.carbon.device.mgt.mobile.internal, + !org.wso2.carbon.device.mgt.mobile.impl, + org.wso2.carbon.device.mgt.mobile.*, + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18 + + + file:src/test/resources/log4j.properties + + + + src/test/resources/testng.xml + + + + + + + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.carbon + org.wso2.carbon.core + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + org.wso2.carbon + org.wso2.carbon.registry.core + + + org.testng + testng + + + org.apache.tomcat.wso2 + jdbc-pool + + + com.h2database.wso2 + h2-database-engine + test + + + com.google.code.gson + gson + + + com.google.android.gcm + gcm-server + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java new file mode 100644 index 000000000..1bf5322da --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile; + +import org.wso2.carbon.device.mgt.common.*; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager; + +import java.util.List; + +public abstract class AbstractMobileOperationManager implements OperationManager { + + @Override + public List getOperations(DeviceIdentifier deviceIdentifier) throws OperationManagementException { + return null; + } + + @Override + public int addOperation(Operation operation, List devices) throws + OperationManagementException { + return 1; + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java new file mode 100644 index 000000000..649786c43 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile; + +public interface DataSourceListener { + + void notifyObserver(); + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java new file mode 100644 index 000000000..5a9e5b8f4 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java @@ -0,0 +1,52 @@ +/* + * * + * * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * * + * * Licensed 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.wso2.carbon.device.mgt.mobile; + +public class DataSourceNotAvailableException extends RuntimeException { + + private String message; + private static final long serialVersionUID = 2021891706072918866L; + + public DataSourceNotAvailableException(String message, Exception nestedException) { + super(message, nestedException); + setErrorMessage(message); + } + + public DataSourceNotAvailableException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public DataSourceNotAvailableException(String message) { + super(message); + setErrorMessage(message); + } + + public DataSourceNotAvailableException(Throwable cause) { + super(cause); + } + + public String getMessage() { + return message; + } + + public void setErrorMessage(String errorMessage) { + this.message = errorMessage; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java new file mode 100644 index 000000000..ef2871c28 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.common; + + +public class MobileDeviceMgtPluginException extends Exception{ + + private static final long serialVersionUID = -2297311387874900305L; + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public MobileDeviceMgtPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public MobileDeviceMgtPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public MobileDeviceMgtPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public MobileDeviceMgtPluginException() { + super(); + } + + public MobileDeviceMgtPluginException(Throwable cause) { + super(cause); + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java new file mode 100644 index 000000000..67e793fa5 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.common; + +public class MobilePluginConstants { + public static final String MOBILE_DB_SCRIPTS_FOLDER = "cdm"; + public static final String MOBILE_CONFIG_REGISTRY_ROOT = "/_system/config"; + + public static final String MEDIA_TYPE_XML = "application/xml"; + public static final String CHARSET_UTF8 = "UTF8"; + public static final String LANGUAGE_CODE_ENGLISH_US = "en_US"; + public static final String LANGUAGE_CODE_ENGLISH_UK = "en_UK"; + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java new file mode 100644 index 000000000..07123434d --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config; + +import org.w3c.dom.Document; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; +import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; +import org.wso2.carbon.utils.CarbonUtils; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; +import java.io.File; + +/** + * Class responsible for the mobile device manager configuration initialization. + */ +public class MobileDeviceConfigurationManager { + + private static final String MOBILE_DEVICE_CONFIG_XML_NAME = "mobile-config.xml"; + private static final String MOBILE_DEVICE_PLUGIN_DIRECTORY = "mobile"; + private static final String DEVICE_MGT_PLUGIN_CONFIGS_DIRECTORY = "device-mgt-plugin-configs"; + private MobileDeviceManagementConfig currentMobileDeviceConfig; + private static MobileDeviceConfigurationManager mobileDeviceConfigManager; + + private final String mobileDeviceMgtConfigXMLPath = + CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + + DEVICE_MGT_PLUGIN_CONFIGS_DIRECTORY + + File.separator + + MOBILE_DEVICE_PLUGIN_DIRECTORY + File.separator + MOBILE_DEVICE_CONFIG_XML_NAME; + + public static MobileDeviceConfigurationManager getInstance() { + if (mobileDeviceConfigManager == null) { + synchronized (MobileDeviceConfigurationManager.class) { + if (mobileDeviceConfigManager == null) { + mobileDeviceConfigManager = new MobileDeviceConfigurationManager(); + } + } + } + return mobileDeviceConfigManager; + } + + public synchronized void initConfig() throws DeviceManagementException { + try { + File mobileDeviceMgtConfig = new File(mobileDeviceMgtConfigXMLPath); + Document doc = MobileDeviceManagementUtil.convertToDocument(mobileDeviceMgtConfig); + JAXBContext mobileDeviceMgmtContext = + JAXBContext.newInstance(MobileDeviceManagementConfig.class); + Unmarshaller unmarshaller = mobileDeviceMgmtContext.createUnmarshaller(); + this.currentMobileDeviceConfig = + (MobileDeviceManagementConfig) unmarshaller.unmarshal(doc); + } catch (Exception e) { + throw new DeviceManagementException( + "Error occurred while initializing Mobile Device Management config", e); + } + } + + public MobileDeviceManagementConfig getMobileDeviceManagementConfig() { + return currentMobileDeviceConfig; + } + + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java new file mode 100644 index 000000000..ced99f955 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Represents Mobile Device Mgt configuration. + */ +@XmlRootElement(name = "MobileDeviceMgtConfiguration") +public final class MobileDeviceManagementConfig { + + private MobileDeviceManagementRepository mobileDeviceMgtRepository; + + @XmlElement(name = "ManagementRepository", nillable = false) + public MobileDeviceManagementRepository getMobileDeviceMgtRepository() { + return mobileDeviceMgtRepository; + } + + public void setMobileDeviceMgtRepository( + MobileDeviceManagementRepository mobileDeviceMgtRepository) { + this.mobileDeviceMgtRepository = mobileDeviceMgtRepository; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java new file mode 100644 index 000000000..88369dd84 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config; + +import org.wso2.carbon.device.mgt.mobile.config.datasource.DataSourceConfigAdapter; +import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.List; +import java.util.Map; + +/** + * Class for holding management repository data. + */ +@XmlRootElement(name = "ManagementRepository") +public class MobileDeviceManagementRepository { + + private Map mobileDataSourceConfigMap; + private List mobileDataSourceConfigs; + + public MobileDataSourceConfig getMobileDataSourceConfig(String provider) { + return mobileDataSourceConfigMap.get(provider); + } + + @XmlElement(name = "DataSourceConfigurations") + @XmlJavaTypeAdapter(DataSourceConfigAdapter.class) + public Map getMobileDataSourceConfigMap() { + return mobileDataSourceConfigMap; + } + + public void setMobileDataSourceConfigMap(Map mobileDataSourceConfigMap) { + this.mobileDataSourceConfigMap = mobileDataSourceConfigMap; + } + + public List getMobileDataSourceConfigs() { + return (List) mobileDataSourceConfigMap.values(); + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java new file mode 100644 index 000000000..71675785c --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.config.datasource; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DataSourceConfigAdapter + extends XmlAdapter> { + + @Override + public Map unmarshal(MobileDataSourceConfigurations mobileDataSourceConfigurations) + throws Exception { + + Map mobileDataSourceConfigMap = new HashMap(); + for (MobileDataSourceConfig mobileDataSourceConfig : mobileDataSourceConfigurations + .getMobileDataSourceConfigs()) { + mobileDataSourceConfigMap.put(mobileDataSourceConfig.getType(), mobileDataSourceConfig); + } + return mobileDataSourceConfigMap; + } + + @Override + public MobileDataSourceConfigurations marshal(Map mobileDataSourceConfigMap) + throws Exception { + + MobileDataSourceConfigurations mobileDataSourceConfigurations = new MobileDataSourceConfigurations(); + mobileDataSourceConfigurations.setMobileDataSourceConfigs( + (List) mobileDataSourceConfigMap.values()); + + return mobileDataSourceConfigurations; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java new file mode 100644 index 000000000..603adcedd --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config.datasource; + +import javax.xml.bind.annotation.*; +import java.util.List; + +/** + * Class for hold JndiLookupDefinition of mobile-config.xml at parsing with JAXB. + */ +@XmlRootElement(name = "JndiLookupDefinition") +public class JNDILookupDefinition { + + private String jndiName; + private List jndiProperties; + + @XmlElement(name = "Name", nillable = false) + public String getJndiName() { + return jndiName; + } + + public void setJndiName(String jndiName) { + this.jndiName = jndiName; + } + + @XmlElementWrapper(name = "Environment", nillable = false) + @XmlElement(name = "Property", nillable = false) + public List getJndiProperties() { + return jndiProperties; + } + + public void setJndiProperties(List jndiProperties) { + this.jndiProperties = jndiProperties; + } + + @XmlRootElement(name = "Property") + public static class JNDIProperty { + + private String name; + + private String value; + + @XmlAttribute(name = "Name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + +} + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java new file mode 100644 index 000000000..869aaf12e --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config.datasource; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Class for holding data source configuration in mobile-config.xml at parsing with JAXB. + */ +@XmlRootElement(name = "DataSourceConfiguration") +public class MobileDataSourceConfig { + + private JNDILookupDefinition jndiLookupDefinition; + private String type; + + @XmlElement(name = "JndiLookupDefinition", nillable = true) + public JNDILookupDefinition getJndiLookupDefinition() { + return jndiLookupDefinition; + } + + public void setJndiLookupDefinition(JNDILookupDefinition jndiLookupDefinition) { + this.jndiLookupDefinition = jndiLookupDefinition; + } + + @XmlAttribute(name = "type") + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java new file mode 100644 index 000000000..17e80f5bf --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.config.datasource; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlRootElement(name = "DataSourceConfigurations") +@XmlAccessorType(XmlAccessType.FIELD) +public class MobileDataSourceConfigurations { + + @XmlElement(name = "DataSourceConfiguration", nillable = true) + private List mobileDataSourceConfigs; + + public List getMobileDataSourceConfigs() { + return mobileDataSourceConfigs; + } + + public void setMobileDataSourceConfigs(List mobileDataSourceConfigs) { + this.mobileDataSourceConfigs = mobileDataSourceConfigs; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java new file mode 100644 index 000000000..32bcb8de7 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.mobile.config.datasource.JNDILookupDefinition; +import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +/** + * Factory class used to create MobileDeviceManagement related DAO objects. + */ +public abstract class AbstractMobileDeviceManagementDAOFactory implements MobileDeviceManagementDAOFactory { + + private static final Log log = LogFactory.getLog(AbstractMobileDeviceManagementDAOFactory.class); + private static Map dataSourceMap = new HashMap<>(); + private static boolean isInitialized; + + public static void init(Map mobileDataSourceConfigMap) + throws MobileDeviceMgtPluginException { + DataSource dataSource; + for (String pluginType : mobileDataSourceConfigMap.keySet()) { + if (dataSourceMap.get(pluginType) == null) { + dataSource = AbstractMobileDeviceManagementDAOFactory.resolveDataSource(mobileDataSourceConfigMap.get + (pluginType)); + dataSourceMap.put(pluginType, dataSource); + } + } + isInitialized = true; + } + + public static void init(String key, MobileDataSourceConfig mobileDataSourceConfig) throws + MobileDeviceMgtPluginException { + DataSource dataSource = AbstractMobileDeviceManagementDAOFactory.resolveDataSource(mobileDataSourceConfig); + dataSourceMap.put(key, dataSource); + } + + /** + * Resolve data source from the data source definition. + * + * @param config Mobile data source configuration + * @return data source resolved from the data source definition + */ + public static DataSource resolveDataSource(MobileDataSourceConfig config) { + DataSource dataSource = null; + if (config == null) { + throw new RuntimeException("Device Management Repository data source configuration " + + "is null and thus, is not initialized"); + } + JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition(); + if (jndiConfig != null) { + if (log.isDebugEnabled()) { + log.debug("Initializing Device Management Repository data source using the JNDI " + + "Lookup Definition"); + } + List jndiPropertyList = + jndiConfig.getJndiProperties(); + if (jndiPropertyList != null) { + Hashtable jndiProperties = new Hashtable(); + for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) { + jndiProperties.put(prop.getName(), prop.getValue()); + } + dataSource = + MobileDeviceManagementDAOUtil + .lookupDataSource(jndiConfig.getJndiName(), jndiProperties); + } else { + dataSource = MobileDeviceManagementDAOUtil + .lookupDataSource(jndiConfig.getJndiName(), null); + } + } + return dataSource; + } + + public static Map getDataSourceMap() { + return dataSourceMap; + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java new file mode 100644 index 000000000..161594273 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; + +import org.wso2.carbon.device.mgt.mobile.dto.MobileDevice; +import java.util.List; + +/** + * This class represents the key operations associated with persisting mobile-device related + * information. + */ +public interface MobileDeviceDAO { + + /** + * Fetches a MobileDevice from MDM database. + * + * @param mblDeviceId Id of the Mobile-Device. + * @return MobileDevice corresponding to given device-id. + * @throws MobileDeviceManagementDAOException + */ + MobileDevice getMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException; + + /** + * Adds a new MobileDevice to the MDM database. + * + * @param mobileDevice MobileDevice to be added. + * @return The status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean addMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException; + + /** + * Updates MobileDevice information in MDM database. + * + * @param mobileDevice MobileDevice to be updated. + * @return The status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean updateMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException; + + /** + * Deletes a given MobileDevice from MDM database. + * + * @param mblDeviceId Id of MobileDevice to be deleted. + * @return The status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean deleteMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException; + + /** + * Fetches all MobileDevices from MDM database. + * + * @return List of MobileDevices. + * @throws MobileDeviceManagementDAOException + */ + List getAllMobileDevices() throws MobileDeviceManagementDAOException; + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java new file mode 100644 index 000000000..0b04818d9 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; + +/** + * Custom exception class for mobile device specific data access related exceptions. + */ +public class MobileDeviceManagementDAOException extends Exception { + + private String message; + private static final long serialVersionUID = 2021891706072918865L; + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message and + * nested exception. + * + * @param message error message + * @param nestedException exception + */ + public MobileDeviceManagementDAOException(String message, Exception nestedException) { + super(message, nestedException); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message + * and cause. + * + * @param message the detail message. + * @param cause the cause of this exception. + */ + public MobileDeviceManagementDAOException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message. + * + * @param message the detail message. + */ + public MobileDeviceManagementDAOException(String message) { + super(message); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified and cause. + * + * @param cause the cause of this exception. + */ + public MobileDeviceManagementDAOException(Throwable cause) { + super(cause); + } + + public String getMessage() { + return message; + } + + public void setErrorMessage(String errorMessage) { + this.message = errorMessage; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java new file mode 100644 index 000000000..37a5c311c --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; + +public interface MobileDeviceManagementDAOFactory { + + MobileDeviceDAO getMobileDeviceDAO(); + + MobileFeatureDAO getMobileFeatureDAO(); + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java new file mode 100644 index 000000000..55c77424b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; + +import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; + +import java.util.List; + +/** + * This class represents the key operations associated with persisting mobile feature related + * information. + */ +public interface MobileFeatureDAO { + + /** + * Adds a new MobileFeature to Mobile-Feature table. + * + * @param mobileFeature MobileFeature object that holds data related to the feature to be inserted. + * @return boolean status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean addFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException; + + /** + * Adda a list of MobileFeatures to Mobile-Feature table. + * + * @param mobileFeatures List of MobileFeature objects. + * @return boolean status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean addFeatures(List mobileFeatures) throws MobileDeviceManagementDAOException; + + /** + * Updates a MobileFeature in Mobile-Feature table. + * + * @param mobileFeature MobileFeature object that holds data has to be updated. + * @return The status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean updateFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException; + + /** + * Deletes a MobileFeature from Mobile-Feature table when the feature id is given. + * + * @param mblFeatureId MobileFeature id of the MobileFeature to be deleted. + * @return The status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean deleteFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException; + + /** + * Deletes a MobileFeature from Mobile-Feature table when the feature code is given. + * + * @param mblFeatureCode MobileFeature code of the feature to be deleted. + * @return The status of the operation. + * @throws MobileDeviceManagementDAOException + */ + boolean deleteFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException; + + /** + * Retrieves a given MobileFeature from Mobile-Feature table when the feature id is given. + * + * @param mblFeatureId Feature id of the feature to be retrieved. + * @return MobileFeature object that holds data of the feature represented by featureId. + * @throws MobileDeviceManagementDAOException + */ + MobileFeature getFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException; + + /** + * Retrieves a given MobileFeature from Mobile-Feature table when the feature code is given. + * + * @param mblFeatureCode Feature code of the feature to be retrieved. + * @return MobileFeature object that holds data of the feature represented by featureCode. + * @throws MobileDeviceManagementDAOException + */ + MobileFeature getFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException; + + /** + * Retrieves all MobileFeatures of a MobileDevice type from Mobile-Feature table. + * + * @param deviceType MobileDevice type of the MobileFeatures to be retrieved + * @return MobileFeature object list. + * @throws MobileDeviceManagementDAOException + */ + List getFeatureByDeviceType(String deviceType) throws MobileDeviceManagementDAOException; + + /** + * Retrieve all the MobileFeatures from Mobile-Feature table. + * + * @return MobileFeature object list. + * @throws MobileDeviceManagementDAOException + */ + List getAllFeatures() throws MobileDeviceManagementDAOException; +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java new file mode 100644 index 000000000..86a940fd6 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implementation of MobileFeatureDAO. + */ +public class MobileFeatureDAOImpl implements MobileFeatureDAO { + + private DataSource dataSource; + private static final Log log = LogFactory.getLog(MobileFeatureDAOImpl.class); + + public MobileFeatureDAOImpl(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public boolean addFeature(MobileFeature mobileFeature) + throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = this.getConnection(); + String createDBQuery = + "INSERT INTO AD_FEATURE(CODE, NAME, DESCRIPTION, DEVICE_TYPE) VALUES (?, ?, ?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, mobileFeature.getCode()); + stmt.setString(2, mobileFeature.getName()); + stmt.setString(3, mobileFeature.getDescription()); + stmt.setString(4, mobileFeature.getDeviceType()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + if (log.isDebugEnabled()) { + log.debug("Added a new MobileFeature " + mobileFeature.getCode() + " to the MDM database."); + } + status = true; + } + } catch (SQLException e) { + String msg = "Error occurred while adding feature code - '" + + mobileFeature.getCode() + "' to feature table"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); + } + return status; + } + + @Override + public boolean addFeatures(List mobileFeatures) throws MobileDeviceManagementDAOException { + return false; + } + + @Override + public boolean updateFeature(MobileFeature mobileFeature) + throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = this.getConnection(); + String updateDBQuery = + "UPDATE AD_FEATURE SET CODE = ?, NAME = ?, DESCRIPTION = ?, DEVICE_TYPE = ?" + + " WHERE ID = ?"; + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, mobileFeature.getCode()); + stmt.setString(2, mobileFeature.getName()); + stmt.setString(3, mobileFeature.getDescription()); + stmt.setString(4, mobileFeature.getDeviceType()); + stmt.setInt(5, mobileFeature.getId()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Updated MobileFeature " + mobileFeature.getCode()); + } + } + } catch (SQLException e) { + String msg = "Error occurred while updating the feature with feature code - '" + + mobileFeature.getId() + "'"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); + } + return status; + } + + @Override + public boolean deleteFeatureByCode(String mblFeatureCode) + throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = this.getConnection(); + String deleteDBQuery = + "DELETE FROM AD_FEATURE WHERE CODE = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, mblFeatureCode); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Deleted MobileFeature code " + mblFeatureCode + " from the MDM database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting feature with code - " + mblFeatureCode; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); + } + return status; + } + + @Override + public boolean deleteFeatureById(int mblFeatureId) + throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = this.getConnection(); + String deleteDBQuery = + "DELETE FROM AD_FEATURE WHERE ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setInt(1, mblFeatureId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Deleted MobileFeature id " + mblFeatureId + " from the MDM database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting feature with id - " + mblFeatureId; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); + } + return status; + } + + @Override + public MobileFeature getFeatureByCode(String mblFeatureCode) + throws MobileDeviceManagementDAOException { + Connection conn = null; + PreparedStatement stmt = null; + MobileFeature mobileFeature = null; + ResultSet resultSet = null; + try { + conn = this.getConnection(); + String selectDBQuery = + "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE " + + "WHERE CODE = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, mblFeatureCode); + resultSet = stmt.executeQuery(); + if (resultSet.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(resultSet.getInt(1)); + mobileFeature.setCode(resultSet.getString(2)); + mobileFeature.setName(resultSet.getString(3)); + mobileFeature.setDescription(resultSet.getString(4)); + mobileFeature.setDeviceType(resultSet.getString(5)); + if (log.isDebugEnabled()) { + log.debug("Fetched MobileFeature " + mblFeatureCode + " from the MDM database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching feature code - '" + mblFeatureCode + "'"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); + } + return mobileFeature; + } + + @Override + public MobileFeature getFeatureById(int mblFeatureId) + throws MobileDeviceManagementDAOException { + Connection conn = null; + PreparedStatement stmt = null; + MobileFeature mobileFeature = null; + ResultSet resultSet = null; + try { + conn = this.getConnection(); + String selectDBQuery = + "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE" + + " WHERE ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setInt(1, mblFeatureId); + resultSet = stmt.executeQuery(); + if (resultSet.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(resultSet.getInt(1)); + mobileFeature.setCode(resultSet.getString(2)); + mobileFeature.setName(resultSet.getString(3)); + mobileFeature.setDescription(resultSet.getString(4)); + mobileFeature.setDeviceType(resultSet.getString(5)); + if (log.isDebugEnabled()) { + log.debug("Fetched MobileFeatureId" + mblFeatureId + " from the MDM database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching feature id - '" + mblFeatureId + "'"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); + } + return mobileFeature; + } + + @Override + public List getAllFeatures() throws MobileDeviceManagementDAOException { + Connection conn = null; + PreparedStatement stmt = null; + MobileFeature mobileFeature; + List mobileFeatures = new ArrayList(); + ResultSet resultSet = null; + try { + conn = this.getConnection(); + String selectDBQuery = + "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(resultSet.getInt(1)); + mobileFeature.setCode(resultSet.getString(2)); + mobileFeature.setName(resultSet.getString(3)); + mobileFeature.setDescription(resultSet.getString(4)); + mobileFeature.setDeviceType(resultSet.getString(5)); + mobileFeatures.add(mobileFeature); + } + if (log.isDebugEnabled()) { + log.debug("Fetched all MobileFeatures from the MDM database."); + } + return mobileFeatures; + } catch (SQLException e) { + String msg = "Error occurred while fetching all features.'"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); + } + } + + @Override + public List getFeatureByDeviceType(String deviceType) throws MobileDeviceManagementDAOException { + Connection conn = null; + PreparedStatement stmt = null; + MobileFeature mobileFeature; + List mobileFeatures = new ArrayList<>(); + ResultSet resultSet = null; + try { + conn = this.getConnection(); + String selectDBQuery = + "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE" + + " WHERE DEVICE_TYPE = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, deviceType); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(resultSet.getInt(1)); + mobileFeature.setCode(resultSet.getString(2)); + mobileFeature.setName(resultSet.getString(3)); + mobileFeature.setDescription(resultSet.getString(4)); + mobileFeature.setDeviceType(resultSet.getString(5)); + mobileFeatures.add(mobileFeature); + } + if (log.isDebugEnabled()) { + log.debug("Fetched all MobileFeatures of type " + deviceType + " from the MDM" + + " database."); + } + return mobileFeatures; + } catch (SQLException e) { + String msg = "Error occurred while fetching all features.'"; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); + } + } + + private Connection getConnection() throws MobileDeviceManagementDAOException { + try { + return dataSource.getConnection(); + } catch (SQLException e) { + String msg = "Error occurred while obtaining a connection from the mobile specific " + + "datasource."; + log.error(msg, e); + throw new MobileDeviceManagementDAOException(msg, e); + } + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java new file mode 100644 index 000000000..0f72e82e9 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.mobile.config.datasource.JNDILookupDefinition; +import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementSchemaInitializer; + +import javax.naming.InitialContext; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Hashtable; +import java.util.List; + +/** + * Utility method required by MobileDeviceManagement DAO classes. + */ +public class MobileDeviceManagementDAOUtil { + + private static final Log log = LogFactory.getLog(MobileDeviceManagementDAOUtil.class); + + public static DataSource lookupDataSource(String dataSourceName, + final Hashtable jndiProperties){ + + try { + if (jndiProperties == null || jndiProperties.isEmpty()) { + return (DataSource) InitialContext.doLookup(dataSourceName); + } + final InitialContext context = new InitialContext(jndiProperties); + return (DataSource) context.lookup(dataSourceName); + } catch (Exception e) { + String msg = "Error in looking up data source: " + e.getMessage(); + log.error(msg, e); + throw new RuntimeException(msg + e.getMessage(), e); + } + } + + 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); + } + + /** + * Creates the mobile device management schema. + * + * @param dataSource Mobile data source + */ + public static void setupMobileDeviceManagementSchema(DataSource dataSource, String pluginType) throws MobileDeviceMgtPluginException { + MobileDeviceManagementSchemaInitializer initializer = + new MobileDeviceManagementSchemaInitializer(dataSource, pluginType); + log.info("Initializing mobile device management repository database schema for : " + pluginType); + try { + initializer.createRegistryDatabase(); + } catch (Exception e) { + throw new MobileDeviceMgtPluginException("Error occurred while initializing Mobile Device " + + "Management database schema", e); + } + } + + + /** + * Resolve data source from the data source definition + * + * @param config data source configuration + * @return data source resolved from the data source definition + */ + private static DataSource resolveDataSource(MobileDataSourceConfig config) { + DataSource dataSource = null; + if (config == null) { + throw new RuntimeException( + "data source configuration " + "is null and " + + "thus, is not initialized"); + } + JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition(); + if (jndiConfig != null) { + if (log.isDebugEnabled()) { + log.debug("Initializing data source using the JNDI " + + "Lookup Definition"); + } + List jndiPropertyList = + jndiConfig.getJndiProperties(); + if (jndiPropertyList != null) { + Hashtable jndiProperties = new Hashtable(); + for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) { + jndiProperties.put(prop.getName(), prop.getValue()); + } + dataSource = MobileDeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), jndiProperties); + } else { + dataSource = MobileDeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), null); + } + } + return dataSource; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java new file mode 100644 index 000000000..185168da4 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * DTO of MobileDevice. + */ +public class MobileDevice implements Serializable { + + private String mobileDeviceId; + private String osVersion; + private String model; + private String vendor; + private String latitude; + private String longitude; + private String imei; + private String imsi; + private String serial; + private Map deviceProperties; + + public MobileDevice() { + this.deviceProperties = new HashMap<>(); + } + + public String getMobileDeviceId() { + return mobileDeviceId; + } + + public void setMobileDeviceId(String mobileDeviceId) { + this.mobileDeviceId = mobileDeviceId; + } + + public String getOsVersion() { + return osVersion; + } + + public void setOsVersion(String osVersion) { + this.osVersion = osVersion; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getVendor() { + return vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public String getLatitude() { + return latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } + + public String getLongitude() { + return longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public String getImsi() { + return imsi; + } + + public void setImsi(String imsi) { + this.imsi = imsi; + } + + public String getSerial() { + return serial; + } + + public void setSerial(String serial) { + this.serial = serial; + } + + public Map getDeviceProperties() { + return deviceProperties; + } + + public void setDeviceProperties(Map deviceProperties) { + this.deviceProperties = deviceProperties; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java new file mode 100644 index 000000000..0ae7e68fa --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; + +/** + * DTO of Mobile Device Operation Mappings. + */ +public class MobileDeviceOperationMapping { + + private String deviceId; + private int operationId; + private long sentDate; + private long receivedDate; + private Status status; + + public enum Status { + NEW, INPROGRESS, COMPLETED + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public void setStatus(String status) { + if(Status.NEW.name().equals(status)){ + this.status = Status.NEW; + }else if(Status.INPROGRESS.name().equals(status)){ + this.status = Status.INPROGRESS; + }else if(Status.COMPLETED.name().equals(status)){ + this.status = Status.COMPLETED; + } + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public int getOperationId() { + return operationId; + } + + public void setOperationId(int operationId) { + this.operationId = operationId; + } + + public long getSentDate() { + return sentDate; + } + + public void setSentDate(long sentDate) { + this.sentDate = sentDate; + } + + public long getReceivedDate() { + return receivedDate; + } + + public void setReceivedDate(long receivedDate) { + this.receivedDate = receivedDate; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java new file mode 100644 index 000000000..9ec5d30b3 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; + +import java.io.Serializable; + +/** + * DTO of Mobile features. + */ +public class MobileFeature implements Serializable { + + private int id; + private String deviceType; + private String code; + private String name; + private String description; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDeviceType() { + return deviceType; + } + + public void setDeviceType(String deviceType) { + this.deviceType = deviceType; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java new file mode 100644 index 000000000..cc99849de --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; + +/** + * DTO of Mobile feature property. Represents a property of a mobile feature. + */ +public class MobileFeatureProperty { + + private String property; + private Integer featureID; + + public Integer getFeatureID() { + return featureID; + } + + public void setFeatureID(Integer featureID) { + this.featureID = featureID; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java new file mode 100644 index 000000000..7c0b9040c --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; + +import java.util.List; + +/** + * DTO of MobileOperation. + */ +public class MobileOperation { + + private int operationId; + private String featureCode; + private long createdDate; + private List properties; + + public int getOperationId() { + return operationId; + } + + public void setOperationId(int operationId) { + this.operationId = operationId; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } + + public String getFeatureCode() { + return featureCode; + } + + public void setFeatureCode(String featureCode) { + this.featureCode = featureCode; + } + + public long getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(long createdDate) { + this.createdDate = createdDate; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java new file mode 100644 index 000000000..d18126aff --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; + +/** + * DTO of Mobile Operation property. + */ +public class MobileOperationProperty { + + private int operationId; + private String property; + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public int getOperationId() { + return operationId; + } + + public void setOperationId(int operationId) { + this.operationId = operationId; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java new file mode 100644 index 000000000..d8943def1 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.internal; + +import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; +import org.wso2.carbon.registry.core.service.RegistryService; + +/** + * DataHolder class of Mobile plugins component. + */ +public class MobileDeviceManagementDataHolder { + + private RegistryService registryService; + + private static MobileDeviceManagementDataHolder thisInstance = new MobileDeviceManagementDataHolder(); + + private MobileDeviceManagementDataHolder() { + } + + public static MobileDeviceManagementDataHolder getInstance() { + return thisInstance; + } + + public RegistryService getRegistryService() { + return registryService; + } + + public void setRegistryService(RegistryService registryService) { + this.registryService = registryService; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java new file mode 100644 index 000000000..e08771b3b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceConfigurationManager; +import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceManagementConfig; +import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; +import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.ndatasource.core.DataSourceService; +import org.wso2.carbon.registry.core.service.RegistryService; + +import java.util.Map; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.mobile.impl.internal.MobileDeviceManagementServiceComponent" + * immediate="true" + * @scr.reference name="org.wso2.carbon.ndatasource" + * interface="org.wso2.carbon.ndatasource.core.DataSourceService" + * cardinality="1..1" + * policy="dynamic" + * bind="setDataSourceService" + * unbind="unsetDataSourceService" + * @scr.reference name="registry.service" + * interface="org.wso2.carbon.registry.core.service.RegistryService" cardinality="0..1" + * policy="dynamic" bind="setRegistryService" unbind="unsetRegistryService" + *

      + * Adding reference to API Manager Configuration service is an unavoidable hack to get rid of NPEs thrown while + * initializing APIMgtDAOs attempting to register APIs programmatically. APIMgtDAO needs to be proper cleaned up + * to avoid as an ideal fix + */ +public class MobileDeviceManagementServiceComponent { + + private static final Log log = LogFactory.getLog(MobileDeviceManagementServiceComponent.class); + + protected void activate(ComponentContext ctx) { + + if (log.isDebugEnabled()) { + log.debug("Activating Mobile Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + + /* Initialize the data source configuration */ + MobileDeviceConfigurationManager.getInstance().initConfig(); + MobileDeviceManagementConfig config = MobileDeviceConfigurationManager.getInstance() + .getMobileDeviceManagementConfig(); + Map dsConfigMap = + config.getMobileDeviceMgtRepository().getMobileDataSourceConfigMap(); + + AbstractMobileDeviceManagementDAOFactory.init(dsConfigMap); + + String setupOption = System.getProperty("setup"); + if (setupOption != null) { + if (log.isDebugEnabled()) { + log.debug( + "-Dsetup is enabled. Mobile Device management repository schema initialization is about " + + "to begin"); + } + try { + for (String pluginType : dsConfigMap.keySet()) { + MobileDeviceManagementDAOUtil + .setupMobileDeviceManagementSchema(AbstractMobileDeviceManagementDAOFactory.getDataSourceMap + ().get(pluginType), pluginType); + } + } catch (MobileDeviceMgtPluginException e) { + log.error("Exception occurred while initializing mobile device management database schema", e); + } + } + if (log.isDebugEnabled()) { + log.debug("Mobile Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Mobile Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Mobile Device Management Service Component"); + } + try { + if (log.isDebugEnabled()) { + log.debug( + "Mobile Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Mobile Device Management bundle", e); + } + } + + protected void setDataSourceService(DataSourceService dataSourceService) { + /* This is to avoid mobile device management component getting initialized before the underlying datasources + are registered */ + if (log.isDebugEnabled()) { + log.debug("Data source service set to mobile service component"); + } + } + + protected void unsetDataSourceService(DataSourceService dataSourceService) { + //do nothing + } + + protected void setRegistryService(RegistryService registryService) { + if (log.isDebugEnabled()) { + log.debug("RegistryService acquired"); + } + MobileDeviceManagementDataHolder.getInstance().setRegistryService(registryService); + } + + protected void unsetRegistryService(RegistryService registryService) { + MobileDeviceManagementDataHolder.getInstance().setRegistryService(null); + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java new file mode 100644 index 000000000..f0071a85f --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.mobile.common.MobilePluginConstants; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.dbcreator.DatabaseCreator; + +import javax.sql.DataSource; +import java.io.File; + +/** + * + * Provides methods for initializing the database script. + * + */ +public final class MobileDeviceManagementSchemaInitializer extends DatabaseCreator { + + private static final Log log = LogFactory.getLog(MobileDeviceManagementSchemaInitializer.class); + private static final String setupSQLScriptBaseLocation = + CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + File.separator + + MobilePluginConstants.MOBILE_DB_SCRIPTS_FOLDER + + File.separator + "plugins" + File.separator; + private String pluginType; + + public String getPluginType() { + return pluginType; + } + + public MobileDeviceManagementSchemaInitializer(DataSource dataSource, String pType) { + super(dataSource); + this.pluginType = pType; + } + + protected String getDbScriptLocation(String databaseType) { + String scriptName = databaseType + ".sql"; + String scriptLocation = setupSQLScriptBaseLocation + this.getPluginType() + File.separator + scriptName; + if (log.isDebugEnabled()) { + log.debug("Loading database script from :" + scriptLocation); + } + return scriptLocation; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java new file mode 100644 index 000000000..73612a365 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.mobile.common.MobilePluginConstants; +import org.wso2.carbon.device.mgt.mobile.dto.*; +import org.wso2.carbon.device.mgt.mobile.internal.MobileDeviceManagementDataHolder; +import org.wso2.carbon.registry.api.RegistryException; +import org.wso2.carbon.registry.api.Resource; +import org.wso2.carbon.registry.core.Registry; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.File; +import java.util.*; + +/** + * Provides utility methods required by the mobile device management bundle. + */ +public class MobileDeviceManagementUtil { + + private static final Log log = LogFactory.getLog(MobileDeviceManagementUtil.class); + private static final String MOBILE_DEVICE_IMEI = "IMEI"; + private static final String MOBILE_DEVICE_IMSI = "IMSI"; + private static final String MOBILE_DEVICE_VENDOR = "VENDOR"; + private static final String MOBILE_DEVICE_OS_VERSION = "OS_VERSION"; + private static final String MOBILE_DEVICE_MODEL = "DEVICE_MODEL"; + private static final String MOBILE_DEVICE_LATITUDE = "LATITUDE"; + private static final String MOBILE_DEVICE_LONGITUDE = "LONGITUDE"; + private static final String MOBILE_DEVICE_SERIAL = "SERIAL"; + + public static Document convertToDocument(File file) throws DeviceManagementException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + DocumentBuilder docBuilder = factory.newDocumentBuilder(); + return docBuilder.parse(file); + } catch (Exception e) { + throw new DeviceManagementException( + "Error occurred while parsing file, while converting " + + "to a org.w3c.dom.Document : " + e.getMessage(), e); + } + } + + private static String getPropertyValue(Device device, String property) { + for (Device.Property prop : device.getProperties()) { + if (property.equals(prop.getName())) { + return prop.getValue(); + } + } + return null; + } + + private 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 MobileDevice convertToMobileDevice(Device device) { + MobileDevice mobileDevice = null; + if (device != null) { + mobileDevice = new MobileDevice(); + mobileDevice.setMobileDeviceId(device.getDeviceIdentifier()); + mobileDevice.setImei(getPropertyValue(device, MOBILE_DEVICE_IMEI)); + mobileDevice.setImsi(getPropertyValue(device, MOBILE_DEVICE_IMSI)); + mobileDevice.setModel(getPropertyValue(device, MOBILE_DEVICE_MODEL)); + mobileDevice.setOsVersion(getPropertyValue(device, MOBILE_DEVICE_OS_VERSION)); + mobileDevice.setVendor(getPropertyValue(device, MOBILE_DEVICE_VENDOR)); + mobileDevice.setLatitude(getPropertyValue(device, MOBILE_DEVICE_LATITUDE)); + mobileDevice.setLongitude(getPropertyValue(device, MOBILE_DEVICE_LONGITUDE)); + + if (device.getProperties() != null) { + Map deviceProperties = new HashMap(); + for (Device.Property deviceProperty : device.getProperties()) { + deviceProperties.put(deviceProperty.getName(), deviceProperty.getValue()); + } + + mobileDevice.setDeviceProperties(deviceProperties); + } else { + mobileDevice.setDeviceProperties(new HashMap()); + } + } + return mobileDevice; + } + + public static Device convertToDevice(MobileDevice mobileDevice) { + Device device = null; + if (mobileDevice != null) { + device = new Device(); + List propertyList = new ArrayList(); + propertyList.add(getProperty(MOBILE_DEVICE_IMEI, mobileDevice.getImei())); + propertyList.add(getProperty(MOBILE_DEVICE_IMSI, mobileDevice.getImsi())); + propertyList.add(getProperty(MOBILE_DEVICE_MODEL, mobileDevice.getModel())); + propertyList.add(getProperty(MOBILE_DEVICE_OS_VERSION, mobileDevice.getOsVersion())); + propertyList.add(getProperty(MOBILE_DEVICE_VENDOR, mobileDevice.getVendor())); + if(mobileDevice.getLatitude() != null) { + propertyList.add(getProperty(MOBILE_DEVICE_LATITUDE, mobileDevice.getLatitude())); + } + if(mobileDevice.getLongitude() != null) { + propertyList.add(getProperty(MOBILE_DEVICE_LONGITUDE, mobileDevice.getLongitude())); + } + propertyList.add(getProperty(MOBILE_DEVICE_SERIAL, mobileDevice.getSerial())); + + if (mobileDevice.getDeviceProperties() != null) { + for (Map.Entry deviceProperty : mobileDevice.getDeviceProperties() + .entrySet()) { + propertyList + .add(getProperty(deviceProperty.getKey(), deviceProperty.getValue())); + } + } + + device.setProperties(propertyList); + device.setDeviceIdentifier(mobileDevice.getMobileDeviceId()); + } + return device; + } + + public static MobileOperation convertToMobileOperation(Operation operation) { + MobileOperation mobileOperation = new MobileOperation(); + MobileOperationProperty operationProperty; + List properties = new LinkedList(); + mobileOperation.setFeatureCode(operation.getCode()); + mobileOperation.setCreatedDate(new Date().getTime()); + Properties operationProperties = operation.getProperties(); + for (String key : operationProperties.stringPropertyNames()) { + operationProperty = new MobileOperationProperty(); + operationProperty.setProperty(key); + operationProperty.setValue(operationProperties.getProperty(key)); + properties.add(operationProperty); + } + mobileOperation.setProperties(properties); + return mobileOperation; + } + + public static List getMobileOperationIdsFromMobileDeviceOperations( + List mobileDeviceOperationMappings) { + List mobileOperationIds = new ArrayList(mobileDeviceOperationMappings.size()); + for (MobileDeviceOperationMapping mobileDeviceOperationMapping : mobileDeviceOperationMappings) { + mobileOperationIds.add(mobileDeviceOperationMapping.getOperationId()); + } + return mobileOperationIds; + } + + public static Operation convertMobileOperationToOperation(MobileOperation mobileOperation) { + Operation operation = new Operation(); + Properties properties = new Properties(); + operation.setCode(mobileOperation.getFeatureCode()); + for (MobileOperationProperty mobileOperationProperty : mobileOperation.getProperties()) { + properties + .put(mobileOperationProperty.getProperty(), mobileOperationProperty.getValue()); + } + operation.setProperties(properties); + return operation; + } + + public static MobileFeature convertToMobileFeature(Feature feature) { + MobileFeature mobileFeature = new MobileFeature(); + mobileFeature.setName(feature.getName()); + mobileFeature.setCode(feature.getCode()); + mobileFeature.setDescription(feature.getDescription()); + mobileFeature.setDeviceType(feature.getDeviceType()); + return mobileFeature; + } + + public static Feature convertToFeature(MobileFeature mobileFeature) { + Feature feature = new Feature(); + feature.setDescription(mobileFeature.getDescription()); + feature.setDeviceType(mobileFeature.getDeviceType()); + feature.setCode(mobileFeature.getCode()); + feature.setName(mobileFeature.getName()); + return feature; + } + + public static Registry getConfigurationRegistry() throws MobileDeviceMgtPluginException { + try { + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + return MobileDeviceManagementDataHolder.getInstance().getRegistryService() + .getConfigSystemRegistry( + tenantId); + } catch (RegistryException e) { + throw new MobileDeviceMgtPluginException( + "Error in retrieving conf registry instance: " + + e.getMessage(), e); + } + } + + public static Resource getRegistryResource(String path) throws MobileDeviceMgtPluginException { + try { + if(MobileDeviceManagementUtil.getConfigurationRegistry().resourceExists(path)){ + return MobileDeviceManagementUtil.getConfigurationRegistry().get(path); + } + return null; + } catch (RegistryException e) { + throw new MobileDeviceMgtPluginException("Error in retrieving registry resource : " + + e.getMessage(), e); + } + } + + public static boolean putRegistryResource(String path, + Resource resource) + throws MobileDeviceMgtPluginException { + boolean status; + try { + MobileDeviceManagementUtil.getConfigurationRegistry().beginTransaction(); + MobileDeviceManagementUtil.getConfigurationRegistry().put(path, resource); + MobileDeviceManagementUtil.getConfigurationRegistry().commitTransaction(); + status = true; + } catch (RegistryException e) { + throw new MobileDeviceMgtPluginException( + "Error occurred while persisting registry resource : " + + e.getMessage(), e); + } + return status; + } + + public static String getResourcePath(String resourceName, String platform) { + String regPath = ""; + switch (platform) { + case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID: + regPath = MobilePluginConstants.MOBILE_CONFIG_REGISTRY_ROOT + "/" + + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID + + "/" + resourceName; + break; + case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS: + regPath = MobilePluginConstants.MOBILE_CONFIG_REGISTRY_ROOT + "/" + + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS + + "/" + resourceName; + break; + case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS: + regPath = MobilePluginConstants.MOBILE_CONFIG_REGISTRY_ROOT + "/" + + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS + + "/" + resourceName; + break; + } + return regPath; + } + + public static String getPlatformConfigPath(String platform) { + String regPath = ""; + switch (platform) { + case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID: + regPath = DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID; + break; + case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS: + regPath = DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS; + break; + case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS: + regPath = DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS; + break; + } + return regPath; + } + + public static boolean createRegistryCollection(String path) + throws MobileDeviceMgtPluginException { + try { + if (! MobileDeviceManagementUtil.getConfigurationRegistry().resourceExists(path)) { + Resource resource = MobileDeviceManagementUtil.getConfigurationRegistry().newCollection(); + MobileDeviceManagementUtil.getConfigurationRegistry().beginTransaction(); + MobileDeviceManagementUtil.getConfigurationRegistry().put(path, resource); + MobileDeviceManagementUtil.getConfigurationRegistry().commitTransaction(); + } + return true; + } catch (MobileDeviceMgtPluginException e) { + throw new MobileDeviceMgtPluginException( + "Error occurred while creating a registry collection : " + + e.getMessage(), e); + } catch (RegistryException e) { + throw new MobileDeviceMgtPluginException( + "Error occurred while creating a registry collection : " + + e.getMessage(), e); + } + } + + public static List getMissingFeatures(List supportedFeatures, List existingFeatures) { + HashMap featureHashMap = new HashMap(); + for (Feature feature: existingFeatures) { + featureHashMap.put(feature.getCode(),feature); + } + List missingFeatures = new ArrayList(); + for (Feature supportedFeature : supportedFeatures) { + if (featureHashMap.get(supportedFeature.getCode()) != null) { + continue; + } + missingFeatures.add(supportedFeature); + } + return missingFeatures; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java new file mode 100644 index 000000000..461de8a1a --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceManagementConfig; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.io.File; + +/** + * Class for holding unit-tests related to MobileDeviceManagementConfig class. + */ + +public class MobileDeviceManagementConfigTests { + + private static final Log log = LogFactory.getLog(MobileDeviceManagementConfigTests.class); + private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_MGT_REPOSITORY = + "./src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml"; + private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_DS_CONFIG = + "./src/test/resources/config/malformed-mobile-config-no-ds-config.xml"; + private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_JNDI_CONFIG = + "./src/test/resources/config/malformed-mobile-config-no-jndi-config.xml"; + private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_APIS_CONFIG = + "./src/test/resources/config/malformed-mobile-config-no-apis-config.xml"; + private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_API_CONFIG = + "./src/test/resources/config/malformed-mobile-config-no-api-config.xml"; + private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_API_PUBLISHER_CONFIG = + "./src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml"; + private static final String TEST_CONFIG_SCHEMA_LOCATION = + "./src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd"; + + private Schema schema; + + @BeforeClass + private void initSchema() { + File deviceManagementSchemaConfig = + new File(MobileDeviceManagementConfigTests.TEST_CONFIG_SCHEMA_LOCATION); + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + try { + schema = factory.newSchema(deviceManagementSchemaConfig); + } catch (SAXException e) { + Assert.fail("Invalid schema found", e); + } + } + + @Test + public void testMandateManagementRepositoryElement() { + File malformedConfig = + new File( + MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_MGT_REPOSITORY); + this.validateMalformedConfig(malformedConfig); + } + + @Test + public void testMandateDataSourceConfigurationElement() { + File malformedConfig = new File( + MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_DS_CONFIG); + this.validateMalformedConfig(malformedConfig); + } + + @Test + public void testMandateJndiLookupDefinitionElement() { + File malformedConfig = new File( + MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_JNDI_CONFIG); + this.validateMalformedConfig(malformedConfig); + } + + @Test + public void testMandateAPIPublisherElement() { + File malformedConfig = new File( + MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_API_PUBLISHER_CONFIG); + this.validateMalformedConfig(malformedConfig); + } + + @Test + public void testMandateAPIsElement() { + File malformedConfig = new File( + MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_APIS_CONFIG); + this.validateMalformedConfig(malformedConfig); + } + + @Test + public void testMandateAPIElement() { + File malformedConfig = new File( + MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_API_CONFIG); + this.validateMalformedConfig(malformedConfig); + } + + /** + * Validates a given malformed-configuration file. + */ + private void validateMalformedConfig(File malformedConfig) { + try { + JAXBContext ctx = JAXBContext.newInstance(MobileDeviceManagementConfig.class); + Unmarshaller um = ctx.createUnmarshaller(); + um.setSchema(this.getSchema()); + um.unmarshal(malformedConfig); + Assert.assertTrue(false); + } catch (JAXBException e) { + Throwable linkedException = e.getLinkedException(); + if (!(linkedException instanceof SAXParseException)) { + log.error("Unexpected error occurred while unmarshalling mobile device management config", e); + Assert.assertTrue(false); + } + Assert.assertTrue(true); + } + } + + private Schema getSchema() { + return schema; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java new file mode 100644 index 000000000..fa263f384 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.common; + + +public enum DBTypes { + Oracle("Oracle"),H2("H2"),MySql("MySql"); + + String dbName ; + DBTypes(String dbStrName) { + dbName = dbStrName; + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java new file mode 100644 index 000000000..042e105bf --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.common; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "Type") +public class TestDBConfiguration { + + private String connectionURL; + private String driverClassName; + private String username; + private String password; + + @Override public String toString() { + return "TestDataSourceConfiguration{" + + "ConnectionURL='" + connectionURL + '\'' + + ", DriverClassName='" + driverClassName + '\'' + + ", Username='" + username + '\'' + + ", Password='" + password + '\'' + + ", Type='" + dbType + '\'' + + '}'; + } + + private String dbType; + + @XmlElement(name = "ConnectionURL", nillable = false) + public String getConnectionURL() { + return connectionURL; + } + + public void setConnectionURL(String connectionURL) { + this.connectionURL = connectionURL; + } + + @XmlElement(name = "DriverClassName", nillable = false) + public String getDriverClassName() { + return driverClassName; + } + + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + + @XmlElement(name = "Username", nillable = false) + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @XmlElement(name = "Password", nillable = false) + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @XmlAttribute(name = "name") + public String getType() { + return dbType; + } + + public void setType(String type) { + this.dbType = type; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java new file mode 100644 index 000000000..88092ea41 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.common; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlRootElement(name = "TestDataSourceConfigurations") +public class TestDBConfigurations { + + private List dbTypesList; + + @XmlElement(name = "Type") + public List getDbTypesList() { + return dbTypesList; + } + + public void setDbTypesList(List dbTypesList) { + this.dbTypesList = dbTypesList; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java new file mode 100644 index 000000000..f454f6f06 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.dao.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.impl.common.DBTypes; +import org.wso2.carbon.device.mgt.mobile.impl.common.TestDBConfiguration; +import org.wso2.carbon.device.mgt.mobile.impl.common.TestDBConfigurations; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import java.io.File; +import java.sql.*; + +/** + * This class provides the utility methods needed for DAO related test executions. + */ +public class MobileDatabaseUtils { + + private static final Log log = LogFactory.getLog(MobileDatabaseUtils.class); + public static final String TEST_RESOURCES_DB_CONFIG_FILE = + "src/test/resources/testdbconfig.xml"; + + public static void cleanupResources(Connection conn, Statement 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 TestDBConfiguration getTestDBConfiguration(DBTypes dbType) throws + MobileDeviceManagementDAOException, + DeviceManagementException { + File deviceMgtConfig = new File(TEST_RESOURCES_DB_CONFIG_FILE); + Document doc; + TestDBConfiguration testDBConfiguration = null; + TestDBConfigurations testDBConfigurations; + + doc = MobileDeviceManagementUtil.convertToDocument(deviceMgtConfig); + JAXBContext testDBContext; + + try { + testDBContext = JAXBContext.newInstance(TestDBConfigurations.class); + Unmarshaller unmarshaller = testDBContext.createUnmarshaller(); + testDBConfigurations = (TestDBConfigurations) unmarshaller.unmarshal(doc); + } catch (JAXBException e) { + throw new MobileDeviceManagementDAOException("Error parsing test db configurations", e); + } + + for (TestDBConfiguration testDBConfiguration1 : testDBConfigurations.getDbTypesList()) { + testDBConfiguration = testDBConfiguration1; + if (testDBConfiguration.getType().equals(dbType.toString())) { + break; + } + } + + return testDBConfiguration; + } + + public static void createH2DB(TestDBConfiguration testDBConf) throws Exception { + Connection conn = null; + Statement stmt = null; + try { + Class.forName(testDBConf.getDriverClassName()); + conn = DriverManager.getConnection(testDBConf.getConnectionURL()); + stmt = conn.createStatement(); + stmt.executeUpdate("RUNSCRIPT FROM './src/test/resources/sql/h2.sql'"); + } finally { + cleanupResources(conn, stmt, null); + } + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-config.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-config.xml new file mode 100644 index 000000000..3fad2eceb --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-config.xml @@ -0,0 +1,41 @@ + + + + + + + + + jdbc/MobileIOSDM_DS + + + + + jdbc/MobileAndroidDM_DS + + + + + jdbc/MobileWindowsDM_DS + + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml new file mode 100644 index 000000000..94fb50462 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml @@ -0,0 +1,42 @@ + + + + + + + + jdbc/MobileDM_DS + + + + + + + + enrollment + admin + enrollment + 1.0.0 + http://localhost:9763/ + http,https + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-apis-config.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-apis-config.xml new file mode 100644 index 000000000..743fe6c24 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-apis-config.xml @@ -0,0 +1,42 @@ + + + + + + + + jdbc/MobileDM_DS + + + + + + + + enrollment + admin + enrollment + 1.0.0 + http://localhost:9763/ + http,https + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-ds-config.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-ds-config.xml new file mode 100644 index 000000000..1f1b5ef14 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-ds-config.xml @@ -0,0 +1,42 @@ + + + + + + + + jdbc/MobileDM_DS + + + + + + + + enrollment + admin + enrollment + 1.0.0 + http://localhost:9763/ + http,https + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml new file mode 100644 index 000000000..06dc33761 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml @@ -0,0 +1,42 @@ + + + + + + + + jdbc/MobileDM_DS + + + + + + + + enrollment + admin + enrollment + 1.0.0 + http://localhost:9763/ + http,https + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml new file mode 100644 index 000000000..617742635 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml @@ -0,0 +1,42 @@ + + + + + + + + jdbc/MobileDM_DS + + + + + + + + enrollment + admin + enrollment + 1.0.0 + http://localhost:9763/ + http,https + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd new file mode 100644 index 000000000..ff6435e50 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/log4j.properties b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/log4j.properties new file mode 100644 index 000000000..675d63149 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/log4j.properties @@ -0,0 +1,33 @@ +# +# Copyright 2015 WSO2, Inc. (http://wso2.com) +# +# 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. +# + +# +# This is the log4j configuration file used by WSO2 Carbon +# +# IMPORTANT : Please do not remove or change the names of any +# of the Appenders defined here. The layout pattern & log file +# can be changed using the WSO2 Carbon Management Console, and those +# settings will override the settings in this file. +# + +log4j.rootLogger=DEBUG, STD_OUT + +# Redirect log messages to console +log4j.appender.STD_OUT=org.apache.log4j.ConsoleAppender +log4j.appender.STD_OUT.Target=System.out +log4j.appender.STD_OUT.layout=org.apache.log4j.PatternLayout +log4j.appender.STD_OUT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/sql/h2.sql b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/sql/h2.sql new file mode 100644 index 000000000..78b5b7b8b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/sql/h2.sql @@ -0,0 +1,54 @@ + +-- ----------------------------------------------------- +-- Table `AD_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_DEVICE` ( + `DEVICE_ID` VARCHAR(45) NOT NULL , + `PUSH_TOKEN` VARCHAR(45) NULL DEFAULT NULL , + `IMEI` VARCHAR(45) NULL DEFAULT NULL , + `IMSI` VARCHAR(45) NULL DEFAULT NULL , + `OS_VERSION` VARCHAR(45) NULL DEFAULT NULL , + `DEVICE_MODEL` VARCHAR(45) NULL DEFAULT NULL , + `VENDOR` VARCHAR(45) NULL DEFAULT NULL , + `LATITUDE` VARCHAR(45) NULL DEFAULT NULL, + `LONGITUDE` VARCHAR(45) NULL DEFAULT NULL, + `CHALLENGE` VARCHAR(45) NULL DEFAULT NULL, + `TOKEN` VARCHAR(500) NULL DEFAULT NULL, + `UNLOCK_TOKEN` VARCHAR(500) NULL DEFAULT NULL, + `SERIAL` VARCHAR(45) NULL DEFAULT NULL, + PRIMARY KEY (`DEVICE_ID`) ); + + +-- ----------------------------------------------------- +-- Table `AD_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_FEATURE` ( + `ID` INT NOT NULL AUTO_INCREMENT , + `CODE` VARCHAR(45) NOT NULL, + `NAME` VARCHAR(100) NULL , + `DESCRIPTION` VARCHAR(200) NULL , + `DEVICE_TYPE` VARCHAR(50) NULL , + PRIMARY KEY (`ID`) ); + +-- ----------------------------------------------------- +-- Table `AD_OPERATION` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_OPERATION` ( + `OPERATION_ID` INT NOT NULL AUTO_INCREMENT , + `FEATURE_CODE` VARCHAR(45) NOT NULL , + `CREATED_DATE` BIGINT NULL , + PRIMARY KEY (`OPERATION_ID`)); + + +-- ----------------------------------------------------- +-- Table `AD_FEATURE_PROPERTY` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_FEATURE_PROPERTY` ( + `PROPERTY` VARCHAR(45) NOT NULL , + `FEATURE_ID` INT NOT NULL , + PRIMARY KEY (`PROPERTY`) , + CONSTRAINT `fk_AD_FEATURE_PROPERTY_AD_FEATURE1` + FOREIGN KEY (`FEATURE_ID` ) + REFERENCES `AD_FEATURE` (`ID` ) + ON DELETE NO ACTION + ON UPDATE NO ACTION); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testdbconfig.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testdbconfig.xml new file mode 100644 index 000000000..eee04a324 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testdbconfig.xml @@ -0,0 +1,24 @@ + + + + + + jdbc:h2:mem:cdm-mobile-test-db;DB_CLOSE_DELAY=-1 + org.h2.Driver + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testng.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testng.xml new file mode 100644 index 000000000..f73ab880b --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/test/resources/testng.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/pom.xml b/components/mobile-plugins/mobile-base-plugin/pom.xml new file mode 100644 index 000000000..b2912b562 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/pom.xml @@ -0,0 +1,62 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + mobile-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + mobile-base-plugin + pom + WSO2 Carbon - Mobile Plugins + http://wso2.org + + + org.wso2.carbon.device.mgt.mobile + org.wso2.carbon.device.mgt.mobile.api + org.wso2.carbon.device.mgt.mobile.ui + org.wso2.carbon.device.mgt.mobile.url.printer + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + + diff --git a/components/key-mgt/pom.xml b/components/mobile-plugins/pom.xml similarity index 79% rename from components/key-mgt/pom.xml rename to components/mobile-plugins/pom.xml index 8a4e5f619..7c62f920b 100644 --- a/components/key-mgt/pom.xml +++ b/components/mobile-plugins/pom.xml @@ -17,30 +17,28 @@ ~ under the License. --> - + org.wso2.carbon.devicemgt-plugins carbon-device-mgt-plugins-parent - 1.9.0-SNAPSHOT + 2.1.0-SNAPSHOT ../../pom.xml 4.0.0 org.wso2.carbon.devicemgt-plugins - key-mgt - 1.9.0-SNAPSHOT + mobile-plugins pom - WSO2 Carbon - Oauth Key Management Component + WSO2 Carbon - Mobile Plugins http://wso2.org - org.wso2.carbon.key.mgt.handler.valve + android-plugin + windows-plugin + mobile-base-plugin - @@ -60,5 +58,4 @@ - diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml new file mode 100644 index 000000000..8ee9a2c23 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml @@ -0,0 +1,309 @@ + + + + + + windows-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.windows.agent + WSO2 Carbon - Windows JAX-RS API + Windows JAX-RS API + war + + + + + maven-compiler-plugin + + 1.7 + 1.7 + + 2.3.2 + + + maven-war-plugin + 2.2 + + + ${project.artifactId} + + + + + + + + deploy + + compile + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + compile + + run + + + + + + + + + + + + + + + + + + + client + + test + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + test + + java + + + + + + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-frontend-jaxrs + + + org.apache.cxf + cxf-rt-transports-http + + + org.apache.cxf + cxf-rt-bindings-soap + compile + + + org.apache.cxf + cxf-rt-bindings-http + + + org.apache.ws.security + wss4j + + + org.slf4j + slf4j-api + + + compile + + + org.apache.cxf + cxf-rt-rs-extension-providers + compile + + + org.apache.cxf + cxf-rt-ws-security + + + org.slf4j + slf4j-api + + + + + org.apache.wss4j + wss4j-ws-security-common + + + org.slf4j + slf4j-api + + + + + org.apache.ws.commons.axiom + axiom-api + + + org.apache.ws.commons.axiom + axiom-impl + + + log4j + log4j + + + org.springframework + spring-web + + + + com.sun.xml.ws + jaxws-rt + provided + + + com.sun.xml.messaging.saaj + saaj-impl + + + org.bouncycastle + bcpkix-jdk15on + + + org.bouncycastle + bcprov-jdk15on + + + org.codehaus.plexus + plexus-utils + + + com.madgag.spongycastle + pkix + + + com.madgag.spongycastle + prov + + + com.madgag.spongycastle + core + + + commons-codec.wso2 + commons-codec + + + joda-time + joda-time + + + commons-io + commons-io + + + javax.ws.rs + jsr311-api + + + org.testng + testng + + + org.wso2.carbon + org.wso2.carbon.logging + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + provided + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth.stub + provided + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth + provided + + + javax.cache + cache-api + 0.5 + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + provided + + + org.wso2.tomcat + tomcat-servlet-api + + + com.google.code.gson + gson + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + + + org.codehaus.jettison.wso2 + jettison + 1.1.wso2v1 + + + org.json.wso2 + json + 2.0.0.wso2v1 + + + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/PluginConstants.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/PluginConstants.java new file mode 100644 index 000000000..d61ee584d --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/PluginConstants.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common; + +/** + * PluginConstants class for Windows plugin. This class has inner classes for containing constants for + * each service. + */ +public final class PluginConstants { + + //Service endpoints + public static final String DISCOVERY_SERVICE_ENDPOINT = + "org.wso2.carbon.mdm.mobileservices.windows.services.discovery.DiscoveryService"; + public static final String CERTIFICATE_ENROLLMENT_SERVICE_ENDPOINT = + "org.wso2.carbon.mdm.mobileservices.windows.services.wstep" + + ".CertificateEnrollmentService"; + public static final String CERTIFICATE_ENROLLMENT_POLICY_SERVICE_ENDPOINT = + "org.wso2.carbon.mdm.mobileservices.windows.services.xcep" + + ".CertificateEnrollmentPolicyService"; + + //Services' target namespaces + public static final String DISCOVERY_SERVICE_TARGET_NAMESPACE = + "http://schemas.microsoft.com/windows/management/2012/01/enrollment"; + public static final String DEVICE_ENROLLMENT_SERVICE_TARGET_NAMESPACE = + "http://schemas.microsoft.com/windows/pki/2009/01/enrollment/RSTRC"; + public static final String CERTIFICATE_ENROLLMENT_POLICY_SERVICE_TARGET_NAMESPACE = + "http://schemas.microsoft.com/windows/pki/2009/01/enrollmentpolicy"; + + //Certificate enrollment service urls and namespaces + public static final String WS_TRUST_TARGET_NAMESPACE = + "http://docs.oasis-open.org/ws-sx/ws-trust/200512"; + public static final String WS_SECURITY_TARGET_NAMESPACE = + "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; + public static final String SOAP_AUTHORIZATION_TARGET_NAMESPACE = + "http://schemas.xmlsoap.org/ws/2006/12/authorization"; + + //Certificate enrollment policy service urls and namespaces + public static final String ENROLLMENT_POLICY_TARGET_NAMESPACE = + "http://schemas.microsoft.com/windows/pki/2009/01/enrollmentpolicy"; + public static final String REQUEST_WRAPPER_CLASS_NAME = + "com.microsoft.schemas.windows.pki._2009._01.enrollmentpolicy.GetPolicies"; + public static final String RESPONSE_WRAPPER_CLASS_NAME = + "com.microsoft.schemas.windows.pki._2009._01.enrollmentpolicy.GetPoliciesResponse"; + + //Servlet Context attributes names + public static final String CONTEXT_WAP_PROVISIONING_FILE = "WAP_PROVISIONING_FILE"; + public static final String WINDOWS_PLUGIN_PROPERTIES = "WINDOWS_PLUGIN_PROPERTIES"; + + //Message handler constants + public static final String CONTENT_LENGTH = "Content-Length"; + public static final String SECURITY = "Security"; + public static final String CXF_REQUEST_URI = "org.apache.cxf.request.uri"; + + //Web services media types + public static final String SYNCML_MEDIA_TYPE = "application/vnd.syncml.dm+xml;charset=utf-8"; + + /** + * Discovery service related other constants + */ + public final class Discovery { + private Discovery() { + throw new AssertionError(); + } + + public static final String ENROLL_SUBDOMAIN = "https://EnterpriseEnrollment."; + public static final String CERTIFICATE_ENROLLMENT_POLICY_SERVICE_URL = + "/ENROLLMENTSERVER/PolicyEnrollmentWebservice" + + ".svc"; + public static final String CERTIFICATE_ENROLLMENT_SERVICE_URL = + "/ENROLLMENTSERVER/DeviceEnrollmentWebservice" + + ".svc"; + public static final String ONPREMISE_CERTIFICATE_ENROLLMENT_POLICY = + "/ENROLLMENTSERVER/ONPREMISE/" + + "PolicyEnrollmentWebservice.svc"; + public static final String ONPREMISE_CERTIFICATE_ENROLLMENT_SERVICE_URL = + "/ENROLLMENTSERVER/ONPREMISE/DeviceEnrollmentWebservice.svc"; + public static final String WAB_URL = "/mdm/enrollments/windows/login-agent"; + + } + + /** + * Certificate enrolment policy service related constants + */ + public final class CertificateEnrolmentPolicy { + private CertificateEnrolmentPolicy() { + throw new AssertionError(); + } + + public static final int MINIMAL_KEY_LENGTH = 2048; + public static final int POLICY_SCHEMA = 3; + public static final int HASH_ALGORITHM_OID_REFERENCE = 0; + public static final int OID_REFERENCE = 0; + public static final String OID = "1.3.14.3.2.29"; + public static final String OID_DEFAULT_NAME = "szOID_OIWSEC_sha1RSASign"; + public static final int OID_GROUP = 1; + public static final int OID_REFERENCE_ID = 0; + } + + /** + * Certificate enrollment Service related constants + */ + public final class CertificateEnrolment { + private CertificateEnrolment() { + throw new AssertionError(); + } + + public static final String TOKEN_TYPE = + "http://schemas.microsoft.com/5.0.0" + + ".0/ConfigurationManager/Enrollment/DeviceEnrollmentToken"; + public static final String PARM = "parm"; + public static final String TYPE = "type"; + public static final String VALUE = "value"; + public static final String VALUE_TYPE = + "http://schemas.microsoft.com/5.0.0" + + ".0/ConfigurationManager/Enrollment/DeviceEnrollmentProvisionDoc"; + public static final String ENCODING_TYPE = + "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0" + + ".xsd#base64binary"; + public static final String CA_CERT = "cacert"; + public static final String X_509 = "X.509"; + public static final String PROPERTIES_XML = "properties.xml"; + public static final String WAP_PROVISIONING_XML = "wap-provisioning.xml"; + public static final String PROVIDER = "BC"; + public static final String ALGORITHM = "SHA1withRSA"; + public static final String JKS = "JKS"; + public static final String SECURITY = "Security"; + public static final String WSS_SECURITY_UTILITY = + "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0" + + ".xsd"; + public static final String TIMESTAMP_ID = "Id"; + public static final String TIMESTAMP_U = "u"; + public static final String TIMESTAMP = "Timestamp"; + public static final String TIMESTAMP_0 = "_0"; + public static final String CREATED = "Created"; + public static final String EXPIRES = "Expires"; + public static final String UTF_8 = "utf-8"; + } + + /** + * SynclML service related constants + */ + public final class SyncML { + private SyncML() { + throw new AssertionError(); + } + + public static final String SYNCML_SOURCE = "Source"; + public static final String SYNCML_DATA = "Data"; + public static final String SYNCML_CMD = "Cmd"; + public static final String SYNCML_CHAL = "ChallengeTag"; + public static final String SYNCML_CMD_ID = "CmdID"; + public static final String SYNCML_CMD_REF = "CmdRef"; + public static final String SYNCML_MESSAGE_REF = "MsgRef"; + public static final String SYNCML_LOCATION_URI = "LocURI"; + public static final String SYNCML_TARGET_REF = "TargetRef"; + + public static final int SYNCML_FIRST_MESSAGE_ID = 1; + public static final int SYNCML_SECOND_MESSAGE_ID = 2; + public static final int SYNCML_FIRST_SESSION_ID = 1; + public static final int SYNCML_SECOND_SESSION_ID = 2; + public static final int OSVERSION_POSITION = 0; + public static final int DEVICE_ID_POSITION = 0; + public static final int DEVICE_MODEL_POSITION = 2; + public static final int DEVICE_MAN_POSITION = 1; + public static final int DEVICE_MOD_VER_POSITION = 3; + public static final int DEVICE_LANG_POSITION = 4; + public static final int IMSI_POSITION = 1; + public static final int IMEI_POSITION = 2; + public static final int VENDER_POSITION = 4; + public static final int MODEL_POSITION = 5; + public static final int MACADDRESS_POSITION = 7; + public static final int RESOLUTION_POSITION = 8; + public static final int DEVICE_NAME_POSITION = 9; + public static final String SYNCML_DATA_ONE = "1"; + public static final String SYNCML_DATA_ZERO = "0"; + public static final String OS_VERSION = "OS_VERSION"; + public static final String IMSI = "IMSI"; + public static final String IMEI = "IMEI"; + public static final String VENDOR = "VENDOR"; + public static final String MODEL = "DEVICE_MODEL"; + public static final String MAC_ADDRESS = "MAC_ADDRESS"; + public static final String DEVICE_INFO = "DEVICE_INFO"; + public static final String DEVICE_NAME = "DEVICE_NAME"; + public static final String SOFTWARE_VERSION = "SOFTWARE_VERSION"; + public static final String DEV_ID = "DEV_ID"; + public static final String MANUFACTURER = "MANUFACTURER"; + public static final String LANGUAGE = "LANGUAGE"; + public static final String RESOLUTION = "RESOLUTION"; + } + + /** + * Windows device constants. + */ + public final class DeviceConstants { + private DeviceConstants() { + throw new AssertionError(); + } + + public static final String DEVICE_ID_NOT_FOUND = "Device Id not found for device found at %s"; + public static final String DEVICE_ID_SERVICE_NOT_FOUND = + "Issue in retrieving device management service instance for device found at %s"; + } + + /** + * Device Operation codes. + */ + public final class OperationCodes { + private OperationCodes() { + throw new AssertionError(); + } + + public static final String DEVICE_LOCK = "DEVICE_LOCK"; + public static final String DISENROLL = "DISENROLL"; + public static final String DEVICE_RING = "DEVICE_RING"; + public static final String WIPE_DATA = "WIPE_DATA"; + public static final String ENCRYPT_STORAGE = "ENCRYPT_STORAGE"; + public static final String LOCK_RESET = "LOCK_RESET"; + public static final String PIN_CODE = "LOCK_PIN"; + public static final String CAMERA = "CAMERA"; + public static final String PASSCODE_POLICY = "PASSCODE_POLICY"; + public static final String PASSWORD_EXPIRE = "PASSWORD_EXPIRE"; + public static final String PASSWORD_HISTORY = "PASSWORD_HISTORY"; + public static final String MAX_PASSWORD_INACTIVE_TIME = "MAX_PASSWORD_INACTIVE_TIME"; + public static final String MIN_PASSWORD_COMPLEX_CHARACTERS = "MIN_PASSWORD_COMPLEX_CHARACTERS"; + public static final String ALPHANUMERIC_PASSWORD = "ALPHANUMERIC_PASSWORD"; + public static final String SIMPLE_PASSWORD = "SIMPLE_PASSWORD"; + public static final String MIN_PASSWORD_LENGTH = "MIN_PASSWORD_LENGTH"; + public static final String DEVICE_PASSWORD_ENABLE = "DEVICE_PASSWORD_ENABLE"; + public static final String PASSWORD_MAX_FAIL_ATTEMPTS = "PASSWORD_MAX_FAIL_ATTEMPTS"; + public static final String MONITOR = "MONITOR"; + public static final String CAMERA_STATUS = "CAMERA_STATUS"; + public static final String POLICY_BUNDLE = "POLICY_BUNDLE"; + public static final String ENCRYPT_STORAGE_STATUS = "ENCRYPT_STORAGE_STATUS"; + public static final String DEVICE_PASSWORD_STATUS = "DEVICE_PASSWORD_STATUS"; + public static final String DEVICE_PASSCODE_DELETE = "DEVICE_PASSCODE_DELETE"; + } + + /** + * Plugin response status code constants. + */ + public final class StatusCodes { + private StatusCodes() { + throw new AssertionError(); + } + + public static final int MULTI_STATUS_HTTP_CODE = 207; + } + + /** + * Tenant Configuration related constants. + */ + public final class TenantConfigProperties { + private TenantConfigProperties() { + throw new AssertionError(); + } + + public static final String LICENSE_KEY = "windowsLicense"; + public static final String LANGUAGE_US = "en_US"; + public static final String CONTENT_TYPE_TEXT = "text"; + public static final String NOTIFIER_FREQUENCY = "notifierFrequency"; + public static final String DEFAULT_FREQUENCY = "8"; + + } + + /** + * Policy Configuration related constants. + */ + public final class PolicyConfigProperties { + private PolicyConfigProperties() { + throw new AssertionError(); + } + + public static final String POLICY_ENABLE = "enabled"; + public static final String ENCRYPTED_ENABLE = "encrypted"; + public static final String ENABLE_PASSWORD = "enablePassword"; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/SyncmlCommandType.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/SyncmlCommandType.java new file mode 100644 index 000000000..6f4969231 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/SyncmlCommandType.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common; + +public enum SyncmlCommandType { + + WIFI("WIFI"); + + private final String commandType; + + SyncmlCommandType(final String commandType) { + this.commandType = commandType; + } + + public String getValue() { + return this.commandType; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/CacheEntry.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/CacheEntry.java new file mode 100644 index 000000000..a160cced1 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/CacheEntry.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.beans; + +/** + * Class for java CacheEntry + */ +public class CacheEntry { + private String deviceID; + private String username; + private String ownership; + + public String getOwnership() { + return ownership; + } + + public void setOwnership(String ownership) { + this.ownership = ownership; + } + + public String getDeviceID() { + return deviceID; + } + + public void setDeviceID(String deviceID) { + this.deviceID = deviceID; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/Token.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/Token.java new file mode 100644 index 000000000..cabbbf96d --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/Token.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.beans; + +/** + * Class for challenge token + */ +public class Token { + private String challengeToken; + + public String getChallengeToken() { + return challengeToken; + } + + public void setChallengeToken(String challengeToken) { + this.challengeToken = challengeToken; + } +} + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/WindowsPluginProperties.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/WindowsPluginProperties.java new file mode 100644 index 000000000..d25b1a5ca --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/WindowsPluginProperties.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.beans; + +/** + * Bean class for storing Windows plugin properties after reading the property file. + */ +public class WindowsPluginProperties { + + private String keyStorePassword; + private String privateKeyPassword; + private String commonName; + private String authPolicy; + private String domain; + private int notBeforeDays; + private int notAfterDays; + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public String getPrivateKeyPassword() { + return privateKeyPassword; + } + + public String getCommonName() { + return commonName; + } + + public int getNotBeforeDays() { + return notBeforeDays; + } + + public int getNotAfterDays() { + return notAfterDays; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public void setPrivateKeyPassword(String privateKeyPassword) { + this.privateKeyPassword = privateKeyPassword; + } + + public void setCommonName(String commonName) { + this.commonName = commonName; + } + + public void setNotBeforeDays(int notBeforeDays) { + this.notBeforeDays = notBeforeDays; + } + + public void setNotAfterDays(int notAfterDays) { + this.notAfterDays = notAfterDays; + } + + public String getAuthPolicy() { + return authPolicy; + } + + public void setAuthPolicy(String authPolicy) { + this.authPolicy = authPolicy; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + +} + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/AuthenticationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/AuthenticationException.java new file mode 100644 index 000000000..8e827ce77 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/AuthenticationException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for authentication failures in windows device enrollment. + */ +public class AuthenticationException extends Exception { + + private String errorMessage; + + public AuthenticationException(String message) { + super(message); + setErrorMessage(message); + } + + public AuthenticationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public AuthenticationException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public AuthenticationException(Throwable cause) { + super(cause); + } + + public AuthenticationException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/BadRequestException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/BadRequestException.java new file mode 100644 index 000000000..fce28a3b5 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/BadRequestException.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +import org.wso2.carbon.mdm.mobileservices.windows.common.util.Message; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Exception class for bad request failures + */ +public class BadRequestException extends WebApplicationException { + + public BadRequestException(Message message, MediaType mediaType) { + super(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(message). + type(mediaType).build()); + } +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/CertificateGenerationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/CertificateGenerationException.java new file mode 100644 index 000000000..ce2f135db --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/CertificateGenerationException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for Certificate generation failures in WSTEP stage. + */ +public class CertificateGenerationException extends Exception { + + private String errorMessage; + + public CertificateGenerationException(String message) { + super(message); + setErrorMessage(message); + } + + public CertificateGenerationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public CertificateGenerationException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public CertificateGenerationException(Throwable cause) { + super(cause); + } + + public CertificateGenerationException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/FileOperationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/FileOperationException.java new file mode 100644 index 000000000..4fbc04398 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/FileOperationException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for file reading/writing failures. + */ +public class FileOperationException extends Exception { + + private String errorMessage; + + public FileOperationException(String message) { + super(message); + setErrorMessage(message); + } + + public FileOperationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public FileOperationException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public FileOperationException(Throwable cause) { + super(cause); + } + + public FileOperationException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/KeyStoreGenerationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/KeyStoreGenerationException.java new file mode 100644 index 000000000..4a783abda --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/KeyStoreGenerationException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for Keystore generation failures. + */ +public class KeyStoreGenerationException extends Exception { + + private String errorMessage; + + public KeyStoreGenerationException(String message) { + super(message); + setErrorMessage(message); + } + + public KeyStoreGenerationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public KeyStoreGenerationException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public KeyStoreGenerationException(Throwable cause) { + super(cause); + } + + public KeyStoreGenerationException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/MDMAPIException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/MDMAPIException.java new file mode 100644 index 000000000..98553785b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/MDMAPIException.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * MDMAPIUtils class provides utility function used by CDM REST-API classes. + */ +public class MDMAPIException extends Exception { + + private static final long serialVersionUID = 7950151650447893900L; + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public MDMAPIException(String msg, Exception e) { + super(msg, e); + setErrorMessage(msg); + } + + public MDMAPIException(String msg, Throwable cause) { + super(msg, cause); + setErrorMessage(msg); + } + + public MDMAPIException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public MDMAPIException() { + super(); + } + + public MDMAPIException(Throwable cause) { + super(cause); + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlMessageFormatException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlMessageFormatException.java new file mode 100644 index 000000000..e37b8b6b5 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlMessageFormatException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for bad format syncml message exceptions. + */ +public class SyncmlMessageFormatException extends Exception { + private String errorMessage; + + public SyncmlMessageFormatException(String message) { + super(message); + setErrorMessage(message); + } + + public SyncmlMessageFormatException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public SyncmlMessageFormatException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public SyncmlMessageFormatException(Throwable cause) { + super(cause); + } + + public SyncmlMessageFormatException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlOperationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlOperationException.java new file mode 100644 index 000000000..409ca57e0 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlOperationException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for syncml Operation and policy related errors. + */ +public class SyncmlOperationException extends Exception { + + private String errorMessage; + + public SyncmlOperationException(String message) { + super(message); + setErrorMessage(message); + } + + public SyncmlOperationException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public SyncmlOperationException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public SyncmlOperationException(Throwable cause) { + super(cause); + } + + public SyncmlOperationException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WAPProvisioningException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WAPProvisioningException.java new file mode 100644 index 000000000..d23368332 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WAPProvisioningException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for property/provisioning XML file reading failures. + */ +public class WAPProvisioningException extends Exception { + + private String errorMessage; + + public WAPProvisioningException(String message) { + super(message); + setErrorMessage(message); + } + + public WAPProvisioningException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public WAPProvisioningException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public WAPProvisioningException(Throwable cause) { + super(cause); + } + + public WAPProvisioningException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsConfigurationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsConfigurationException.java new file mode 100644 index 000000000..86c49eef2 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsConfigurationException.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Custom class for windows API configurations. + */ +public class WindowsConfigurationException extends Exception { + + private String errorMessage; + + private static final long serialVersionUID = 7950151650447893900L; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public WindowsConfigurationException(Throwable cause) { + super(cause); + } + + public WindowsConfigurationException() { + super(); + } + + public WindowsConfigurationException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public WindowsConfigurationException(String msg, Throwable cause) { + super(msg, cause); + setErrorMessage(msg); + } + + public WindowsConfigurationException(String msg, Exception exception) { + super(msg, exception); + setErrorMessage(msg); + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsDeviceEnrolmentException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsDeviceEnrolmentException.java new file mode 100644 index 000000000..4722b7621 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsDeviceEnrolmentException.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +/** + * Exception class for general WSTEP messaging/message generation failures. + */ +public class WindowsDeviceEnrolmentException extends Exception { + + private String errorMessage; + + public WindowsDeviceEnrolmentException(String message) { + super(message); + setErrorMessage(message); + } + + public WindowsDeviceEnrolmentException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public WindowsDeviceEnrolmentException(String message, Exception nestedEx) { + super(message, nestedEx); + setErrorMessage(message); + } + + public WindowsDeviceEnrolmentException(Throwable cause) { + super(cause); + } + + public WindowsDeviceEnrolmentException() { + super(); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsOperationsException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsOperationsException.java new file mode 100644 index 000000000..14677391d --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsOperationsException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.exceptions; + +import org.wso2.carbon.mdm.mobileservices.windows.common.util.Message; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Exception Class for windows operations related exceptions + */ +public class WindowsOperationsException extends WebApplicationException { + + public WindowsOperationsException(Message message, MediaType mediaType) { + super(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(message). + type(mediaType).build()); + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/AuthenticationInfo.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/AuthenticationInfo.java new file mode 100644 index 000000000..80458a50a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/AuthenticationInfo.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +/** + * DTO class to hold the information of authenticated user. + */ +public class AuthenticationInfo { + private String message; + private String username; + private String tenantDomain; + private int tenantId = -1; + + public String getUsername() { + return username; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getTenantDomain() { + return tenantDomain; + } + + public void setTenantDomain(String tenantDomain) { + this.tenantDomain = tenantDomain; + } + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/BSTValidator.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/BSTValidator.java new file mode 100644 index 000000000..916f2bf7b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/BSTValidator.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ws.security.WSSecurityException; +import org.apache.ws.security.handler.RequestData; +import org.apache.ws.security.message.token.BinarySecurity; +import org.apache.ws.security.validate.Credential; +import org.apache.ws.security.validate.Validator; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationRequestDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2TokenValidationResponseDTO; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.CacheEntry; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.AuthenticationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.util.HashMap; + +/** + * Validator class for user authentication checking the default carbon user store. + */ +public class BSTValidator implements Validator { + + private static Log log = LogFactory.getLog(BSTValidator.class); + private static final String BEARER_TOKEN_TYPE = "bearer"; + private static final String RESOURCE_KEY = "resource"; + + /** + * This method validates the binary security token in SOAP message coming from the device. + * + * @param credential - binary security token credential object + * @param requestData - Request data associated with the request + * @return - Credential object if authentication is success, or null if not success + * @throws WSSecurityException + */ + @Override + public Credential validate(Credential credential, RequestData requestData) throws WSSecurityException { + String encodedBinarySecurityToken; + String requestedUri; + Credential returnCredentials = null; + + HashMap msgContext = (HashMap) requestData.getMsgContext(); + requestedUri = msgContext.get(PluginConstants.CXF_REQUEST_URI).toString(); + BinarySecurity binarySecurityTokenObject = credential.getBinarySecurityToken(); + String binarySecurityToken = binarySecurityTokenObject.getElement().getFirstChild().getTextContent(); + Base64 base64 = new Base64(); + encodedBinarySecurityToken = new String(base64.decode(binarySecurityToken)); + AuthenticationInfo authenticationInfo; + try { + authenticationInfo = validateRequest(requestedUri, encodedBinarySecurityToken); + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext privilegedCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + privilegedCarbonContext.setTenantId(authenticationInfo.getTenantId()); + privilegedCarbonContext.setTenantDomain(authenticationInfo.getTenantDomain()); + privilegedCarbonContext.setUsername(authenticationInfo.getUsername()); + + if (authenticate(binarySecurityToken)) { + returnCredentials = credential; + } else { + String msg = "Authentication failure due to invalid binary security token."; + log.error(msg); + throw new WindowsDeviceEnrolmentException(msg); + } + } catch (AuthenticationException e) { + String msg = "Failure occurred in the BST validator."; + log.error(msg, e); + throw new WSSecurityException(msg, e); + } catch (WindowsDeviceEnrolmentException e) { + String msg = "Authentication Failure occurred due to binary security token."; + log.error(msg, e); + throw new WSSecurityException(msg, e); + } + return returnCredentials; + } + + /** + * This method authenticates the user checking the binary security token in the user store. + * + * @param binarySecurityToken - Binary security token received in the SOAP message header + * @return - Authentication status + * @throws AuthenticationException + */ + public boolean authenticate(String binarySecurityToken) throws + AuthenticationException { + + CacheEntry cacheentry = (CacheEntry) DeviceUtil.getCacheEntry(binarySecurityToken); + String username = cacheentry.getUsername(); + return username != null; + } + + /** + * Validate SOAP request token. + * + * @param requestedUri- Requested endpoint URI. + * @param encodedBinarySecurityToken-Binary security token comes from the soap request message. + * @return returns authorized user information. + * @throws WindowsDeviceEnrolmentException + */ + public AuthenticationInfo validateRequest(String requestedUri, String encodedBinarySecurityToken) + throws WindowsDeviceEnrolmentException { + + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + // Create a OAuth2TokenValidationRequestDTO object for validating access token + OAuth2TokenValidationRequestDTO dto = new OAuth2TokenValidationRequestDTO(); + //Set the access token info + OAuth2TokenValidationRequestDTO.OAuth2AccessToken oAuth2AccessToken = dto.new OAuth2AccessToken(); + oAuth2AccessToken.setTokenType(BSTValidator.BEARER_TOKEN_TYPE); + oAuth2AccessToken.setIdentifier(encodedBinarySecurityToken); + dto.setAccessToken(oAuth2AccessToken); + + //Set the resource context param. This will be used in scope validation. + OAuth2TokenValidationRequestDTO.TokenValidationContextParam + resourceContextParam = dto.new TokenValidationContextParam(); + resourceContextParam.setKey(BSTValidator.RESOURCE_KEY); + resourceContextParam.setValue(requestedUri + ":POST"); + + OAuth2TokenValidationRequestDTO.TokenValidationContextParam[] + tokenValidationContextParams = + new OAuth2TokenValidationRequestDTO.TokenValidationContextParam[1]; + tokenValidationContextParams[0] = resourceContextParam; + dto.setContext(tokenValidationContextParams); + try { + OAuth2TokenValidationResponseDTO oAuth2TokenValidationResponseDTO = + WindowsAPIUtils.getOAuth2TokenValidationService().validate(dto); + if (oAuth2TokenValidationResponseDTO.isValid()) { + String username = oAuth2TokenValidationResponseDTO.getAuthorizedUser(); + authenticationInfo.setUsername(username); + authenticationInfo.setTenantDomain(MultitenantUtils.getTenantDomain(username)); + authenticationInfo.setTenantId(WindowsAPIUtils.getTenantIdOFUser(username)); + } else { + authenticationInfo.setMessage(oAuth2TokenValidationResponseDTO.getErrorMsg()); + } + } catch (DeviceManagementException e) { + String msg = "Authentication failure due to invalid binary security token."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } + return authenticationInfo; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ConfigInitializerContextListener.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ConfigInitializerContextListener.java new file mode 100644 index 000000000..b2eda4a4f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ConfigInitializerContextListener.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.WindowsPluginProperties; +import org.xml.sax.SAXException; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.IOException; + +/** + * This class performs one time operations. + */ +public class ConfigInitializerContextListener implements ServletContextListener { + + public static final int INITIAL_VALUE = 0; + private static Log log = LogFactory.getLog(ConfigInitializerContextListener.class); + + private enum PropertyName { + PROPERTY_SIGNED_CERT_CN("SignedCertCN"), + PROPERTY_SIGNED_CERT_NOT_BEFORE("SignedCertNotBefore"), + PROPERTY_SIGNED_CERT_NOT_AFTER("SignedCertNotAfter"), + PROPERTY_PASSWORD("Password"), + PROPERTY_PRIVATE_KEY_PASSWORD("PrivateKeyPassword"), + AUTH_POLICY("AuthPolicy"), + DOMAIN("domain"); + + private final String propertyName; + + PropertyName(final String propertyName) { + this.propertyName = propertyName; + } + + public String getValue() { + return this.propertyName; + } + } + + /** + * This method loads wap-provisioning file / property file, sets wap-provisioning file and + * extracted properties as attributes in servlet context. + * + * @param servletContextEvent - Uses when servlet communicating with servlet container. + */ + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + + ServletContext servletContext = servletContextEvent.getServletContext(); + File propertyFile = new File(getClass().getClassLoader().getResource( + PluginConstants.CertificateEnrolment.PROPERTIES_XML).getFile()); + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + Document document = null; + try { + docBuilder = docBuilderFactory.newDocumentBuilder(); + if (docBuilder != null) { + document = docBuilder.parse(propertyFile); + } + } catch (ParserConfigurationException e) { + log.error("Parser configuration failure while reading properties.xml."); + } catch (SAXException e) { + log.error("Parsing error occurred while reading properties.xml."); + } catch (IOException e) { + log.error("File reading error occurred while accessing properties.xml."); + } + + String password = null; + String privateKeyPassword = null; + String signedCertCommonName = null; + String authPolicy = null; + String domain = null; + int signedCertNotBeforeDate = INITIAL_VALUE; + int signedCertNotAfterDate = INITIAL_VALUE; + + if (document != null) { + password = document.getElementsByTagName(PropertyName.PROPERTY_PASSWORD.getValue()).item(0). + getTextContent(); + privateKeyPassword = document.getElementsByTagName(PropertyName.PROPERTY_PRIVATE_KEY_PASSWORD.getValue()). + item(0).getTextContent(); + signedCertCommonName = + document.getElementsByTagName(PropertyName.PROPERTY_SIGNED_CERT_CN.getValue()).item(0). + getTextContent(); + authPolicy = document.getElementsByTagName(PropertyName.AUTH_POLICY.getValue()).item(0). + getTextContent(); + signedCertNotBeforeDate = Integer.valueOf(document.getElementsByTagName( + PropertyName.PROPERTY_SIGNED_CERT_NOT_BEFORE.getValue()).item(0).getTextContent()); + signedCertNotAfterDate = Integer.valueOf(document.getElementsByTagName( + PropertyName.PROPERTY_SIGNED_CERT_NOT_AFTER.getValue()).item(0).getTextContent()); + domain = document.getElementsByTagName(PropertyName.DOMAIN.getValue()).item(0).getTextContent(); + + } + + WindowsPluginProperties properties = new WindowsPluginProperties(); + properties.setKeyStorePassword(password); + properties.setPrivateKeyPassword(privateKeyPassword); + properties.setCommonName(signedCertCommonName); + properties.setNotBeforeDays(signedCertNotBeforeDate); + properties.setNotAfterDays(signedCertNotAfterDate); + properties.setAuthPolicy(authPolicy); + properties.setDomain(domain); + servletContext.setAttribute(PluginConstants.WINDOWS_PLUGIN_PROPERTIES, properties); + + File wapProvisioningFile = new File(getClass().getClassLoader().getResource( + PluginConstants.CertificateEnrolment.WAP_PROVISIONING_XML).getFile()); + servletContext.setAttribute(PluginConstants.CONTEXT_WAP_PROVISIONING_FILE, wapProvisioningFile); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceIDHolder.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceIDHolder.java new file mode 100644 index 000000000..99b0a5d2e --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceIDHolder.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; + +import java.util.List; + +/** + * Class for holding device ids. + */ +public class DeviceIDHolder { + + private List errorDeviceIdList; + private List validDeviceIDList; + + public List getErrorDeviceIdList() { + return errorDeviceIdList; + } + + public void setErrorDeviceIdList(List errorDeviceIdList) { + this.errorDeviceIdList = errorDeviceIdList; + } + + public List getValidDeviceIDList() { + return validDeviceIDList; + } + + public void setValidDeviceIDList(List validDeviceIDList) { + this.validDeviceIDList = validDeviceIDList; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceUtil.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceUtil.java new file mode 100644 index 000000000..61d2713b2 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.CacheEntry; + +import javax.cache.Cache; +import javax.cache.CacheConfiguration; +import javax.cache.CacheManager; +import javax.cache.Caching; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * Class for generate random token for XCEP and WSTEP + */ +public class DeviceUtil { + + private static final String TOKEN_CACHE_MANAGER = "TOKEN_CACHE_MANAGER"; + private static final String TOKEN_CACHE = "TOKEN_CACHE"; + private static final long CACHE_DURATION = 15l; + private static boolean isContextCacheInitialized = false; + + public static String generateRandomToken() { + return String.valueOf(UUID.randomUUID()); + } + + public static void persistChallengeToken(String token, String deviceID, String username) throws DeviceManagementException { + + Object objCacheEntry = getCacheEntry(token); + CacheEntry cacheEntry; + if (objCacheEntry == null) { + cacheEntry = new CacheEntry(); + cacheEntry.setUsername(username); + } else { + cacheEntry = (CacheEntry) objCacheEntry; + } + if (deviceID != null) { + cacheEntry.setDeviceID(deviceID); + } + getTokenCache().put(token, cacheEntry); + } + + public static void removeToken(String token) { + getTokenCache().remove(token); + } + + public static Object getCacheEntry(String token) { + return getTokenCache().get(token); + } + + private static Cache getTokenCache() { + CacheManager contextCacheManager = Caching.getCacheManager(TOKEN_CACHE_MANAGER). + getCache(TOKEN_CACHE).getCacheManager(); + if (!isContextCacheInitialized) { + isContextCacheInitialized = true; + return contextCacheManager.createCacheBuilder(TOKEN_CACHE_MANAGER).setExpiry( + CacheConfiguration.ExpiryType.MODIFIED, + new CacheConfiguration.Duration(TimeUnit.MINUTES, CACHE_DURATION)).setStoreByValue(false).build(); + } else { + return Caching.getCacheManager(TOKEN_CACHE_MANAGER).getCache(TOKEN_CACHE); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorHandler.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorHandler.java new file mode 100644 index 000000000..2640302a5 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; + +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * Class for handle response exceptions. + */ +@Produces({"application/json", "application/xml"}) +public class ErrorHandler implements ExceptionMapper { + + public Response toResponse(WindowsConfigurationException exception) { + ErrorMessage errorMessage = new ErrorMessage(); + errorMessage.setErrorMessage(exception.getErrorMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build(); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorMessage.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorMessage.java new file mode 100644 index 000000000..42177b230 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorMessage.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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. + */ +/** + * Generate Error Messages for responses. + */ +package org.wso2.carbon.mdm.mobileservices.windows.common.util; + +public class ErrorMessage { + + private String errorMessage; + private String errorCode; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getErrorCode() { + return errorCode; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/GsonMessageBodyHandler.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/GsonMessageBodyHandler.java new file mode 100644 index 000000000..eaed2e11a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/GsonMessageBodyHandler.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +/** + * Class for parse Gson Messages. + */ +@Provider +@Produces(APPLICATION_JSON) +@Consumes(APPLICATION_JSON) +public class GsonMessageBodyHandler implements MessageBodyWriter, MessageBodyReader { + private Gson gson; + private static final String UTF_8 = "UTF-8"; + + public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return true; + } + + private Gson getGson() { + if (gson == null) { + final GsonBuilder gsonBuilder = new GsonBuilder(); + gson = gsonBuilder.create(); + } + return gson; + } + + public Object readFrom(Class objectClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap stringStringMultivaluedMap, InputStream entityStream) + throws IOException, WebApplicationException { + + InputStreamReader reader = new InputStreamReader(entityStream, "UTF-8"); + + try { + return getGson().fromJson(reader, type); + } finally { + reader.close(); + } + } + + public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return true; + } + + public long getSize(Object o, Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return -1; + } + + public void writeTo(Object object, Class aClass, Type type, Annotation[] annotations, MediaType mediaType, + MultivaluedMap stringObjectMultivaluedMap, OutputStream entityStream) + throws IOException, WebApplicationException { + + OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8); + try { + Type jsonType; + if (type.equals(type)) { + jsonType = type; + } else { + jsonType = type; + } + getGson().toJson(object, jsonType, writer); + } finally { + writer.close(); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/Message.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/Message.java new file mode 100644 index 000000000..c3f2cc793 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/Message.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Class for generate response Messages. + */ +@XmlRootElement +public class Message { + private String responseCode; + private String responseMessage; + + @XmlElement + public String getResponseMessage() { + return responseMessage; + } + + public void setResponseMessage(String responseMessage) { + this.responseMessage = responseMessage; + } + + @XmlElement + public String getResponseCode() { + return responseCode; + } + + public void setResponseCode(String responseCode) { + this.responseCode = responseCode; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/SOAPSecurityHandler.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/SOAPSecurityHandler.java new file mode 100644 index 000000000..679ac010c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/SOAPSecurityHandler.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.namespace.QName; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.soap.SOAPHandler; +import javax.xml.ws.handler.soap.SOAPMessageContext; +import java.util.HashSet; +import java.util.Set; + +/** + * Class for handle SOAP message security. + */ +public class SOAPSecurityHandler implements SOAPHandler { + + /** + * This method resolves the security header coming in the SOAP message. + * + * @return - Security Header + */ + @Override + public Set getHeaders() { + QName securityHeader = new QName(PluginConstants.WS_SECURITY_TARGET_NAMESPACE, PluginConstants.SECURITY); + HashSet headers = new HashSet(); + headers.add(securityHeader); + return headers; + } + + @Override + public boolean handleMessage(SOAPMessageContext context) { + return true; + } + + @Override + public boolean handleFault(SOAPMessageContext context) { + return true; + } + + @Override + public void close(MessageContext context) { + + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/UsernameTokenValidator.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/UsernameTokenValidator.java new file mode 100644 index 000000000..fb9ab5b63 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/UsernameTokenValidator.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ws.security.WSSecurityException; +import org.apache.ws.security.handler.RequestData; +import org.apache.ws.security.validate.Credential; +import org.apache.ws.security.validate.Validator; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.AuthenticationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +/** + * Validator class for user authentication checking the default carbon user store. + */ +public class UsernameTokenValidator implements Validator { + + private static final int USER_SEGMENT = 0; + private static final int DOMAIN_SEGMENT = 1; + private static final String DELIMITER = "@"; + private static Log log = LogFactory.getLog(UsernameTokenValidator.class); + + /** + * This method validates the username token in SOAP message coming from the device. + * + * @param credential - Username token credentials coming from device + * @param requestData - Request data associated with the request + * @return - Credential object if authentication is success, or null if not success + * @throws WSSecurityException + */ + @Override + public Credential validate(Credential credential, RequestData requestData) throws + WSSecurityException { + + String domainUser = credential.getUsernametoken().getName(); + String[] domainUserArray = domainUser.split(DELIMITER); + Credential returnCredentials; + String user = domainUserArray[USER_SEGMENT]; + String domain = domainUserArray[DOMAIN_SEGMENT]; + String password = credential.getUsernametoken().getPassword(); + + try { + if (authenticate(user, password, domain)) { + returnCredentials = credential; + } else { + String msg = "Authentication failure due to incorrect credentials."; + log.error(msg); + throw new WindowsDeviceEnrolmentException(msg); + } + //Generic exception is caught here as there is no need of taking different actions for + //different exceptions. + } catch (AuthenticationException e) { + String msg = "Failure occurred in the BST validator."; + log.error(msg, e); + throw new WSSecurityException(msg, e); + } catch (WindowsDeviceEnrolmentException e) { + String msg = "Authentication Failure occurred due to binary security token."; + log.error(msg, e); + throw new WSSecurityException(msg, e); + } + return returnCredentials; + } + + /** + * This method authenticate the user checking the carbon default user store. + * + * @param username - Username in username token + * @param password - Password in username token + * @param tenantDomain - Tenant domain is extracted from the username + * @return - Returns boolean representing authentication result + * @throws AuthenticationException + */ + public boolean authenticate(String username, String password, String tenantDomain) throws + AuthenticationException { + + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + ctx.setTenantId(MultitenantConstants.SUPER_TENANT_ID); + RealmService realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + + if (realmService == null) { + String msg = "RealmService not initialized."; + log.error(msg); + throw new AuthenticationException(msg); + } + + int tenantId; + if (tenantDomain == null || tenantDomain.trim().isEmpty()) { + tenantId = MultitenantConstants.SUPER_TENANT_ID; + } else { + tenantId = realmService.getTenantManager().getTenantId(tenantDomain); + } + + if (tenantId == MultitenantConstants.INVALID_TENANT_ID) { + String msg = "Invalid tenant domain " + tenantDomain; + log.error(msg); + throw new AuthenticationException(msg); + } + UserRealm userRealm = realmService.getTenantUserRealm(tenantId); + + return userRealm.getUserStoreManager().authenticate(username, password); + } catch (UserStoreException e) { + String msg = "User store is not initialized."; + log.error(msg, e); + throw new AuthenticationException(msg, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsAPIUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsAPIUtils.java new file mode 100644 index 000000000..e1dfb97e9 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsAPIUtils.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.MDMAPIException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; +import org.wso2.carbon.user.api.TenantManager; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.api.UserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Class for get Windows API utilities. + */ +public class WindowsAPIUtils { + + private static Log log = LogFactory.getLog(WindowsAPIUtils.class); + + public static DeviceIdentifier convertToDeviceIdentifierObject(String deviceId) { + DeviceIdentifier identifier = new DeviceIdentifier(); + identifier.setId(deviceId); + identifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + return identifier; + } + + public static CertificateManagementService getCertificateManagementService() { + CertificateManagementService cmService; + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + ctx.setTenantId(MultitenantConstants.SUPER_TENANT_ID); + cmService = + (CertificateManagementService)ctx.getOSGiService(DeviceManagementProviderService.class, null); + PrivilegedCarbonContext.endTenantFlow(); + return cmService; + } + + 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."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } + + + public static UserStoreManager getUserStoreManager() throws MDMAPIException { + RealmService realmService; + UserStoreManager userStoreManager; + try { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + if (realmService == null) { + String msg = "Realm service has not initialized."; + throw new IllegalStateException(msg); + } + int tenantId = ctx.getTenantId(); + userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager(); + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving current user store manager"; + throw new MDMAPIException(msg, e); + } + return userStoreManager; + } + + public static NotificationManagementService getNotificationManagementService() { + NotificationManagementService notificationManagementService; + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + notificationManagementService = (NotificationManagementService) ctx.getOSGiService( + NotificationManagementService.class, null); + if (notificationManagementService == null) { + String msg = "Notification Management service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return notificationManagementService; + } + + public static MediaType getResponseMediaType(String acceptHeader) { + MediaType responseMediaType; + if (MediaType.WILDCARD.equals(acceptHeader)) { + responseMediaType = MediaType.APPLICATION_JSON_TYPE; + } else { + responseMediaType = MediaType.valueOf(acceptHeader); + } + return responseMediaType; + } + + public static Response getOperationResponse(List deviceIDs, Operation operation, + Message message, MediaType responseMediaType) + throws DeviceManagementException, OperationManagementException { + WindowsDeviceUtils deviceUtils = new WindowsDeviceUtils(); + DeviceIDHolder deviceIDHolder = deviceUtils.validateDeviceIdentifiers(deviceIDs, + message, responseMediaType); + getDeviceManagementService().addOperation(operation, deviceIDHolder.getValidDeviceIDList()); + if (!deviceIDHolder.getErrorDeviceIdList().isEmpty()) { + return javax.ws.rs.core.Response.status(PluginConstants.StatusCodes. + MULTI_STATUS_HTTP_CODE).type( + responseMediaType).entity(deviceUtils. + convertErrorMapIntoErrorMessage(deviceIDHolder.getErrorDeviceIdList())).build(); + } + return javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.CREATED). + type(responseMediaType).build(); + } + + public static PolicyManagerService getPolicyManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + PolicyManagerService policyManagerService = (PolicyManagerService) ctx.getOSGiService( + PolicyManagerService.class, null); + if (policyManagerService == null) { + String msg = "Policy Manager service has not initialized"; + log.error(msg); + throw new IllegalStateException(msg); + } + return policyManagerService; + } + + public static void updateOperation(String deviceId, Operation operation) + throws OperationManagementException { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + getDeviceManagementService().updateOperation(deviceIdentifier, operation); + } + + public static TenantConfiguration getTenantConfiguration() throws DeviceManagementException { + return getDeviceManagementService().getConfiguration( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + } + + public static int getTenantIdOFUser(String username) throws DeviceManagementException { + int tenantId = 0; + String domainName = MultitenantUtils.getTenantDomain(username); + if (domainName != null) { + try { + TenantManager tenantManager = IdentityTenantUtil.getRealmService().getTenantManager(); + tenantId = tenantManager.getTenantId(domainName); + } catch (UserStoreException e) { + String errorMsg = "Error when getting the tenant id from the tenant domain : " + + domainName; + log.error(errorMsg, e); + throw new DeviceManagementException(errorMsg, e); + } + } + return tenantId; + } + + public static OAuth2TokenValidationService getOAuth2TokenValidationService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + OAuth2TokenValidationService oAuth2TokenValidationService = + (OAuth2TokenValidationService) ctx.getOSGiService(OAuth2TokenValidationService.class, null); + if (oAuth2TokenValidationService == null) { + String msg = "OAuth2TokenValidation service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return oAuth2TokenValidationService; + } + + public static void startTenantFlow(String userName) { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext privilegedCarbonContext = PrivilegedCarbonContext. + getThreadLocalCarbonContext(); + privilegedCarbonContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID); + privilegedCarbonContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + privilegedCarbonContext.setUsername(userName); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsDeviceUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsDeviceUtils.java new file mode 100644 index 000000000..2d38ac2cb --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsDeviceUtils.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.common.util; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.BadRequestException; + +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.List; + +/** + * Class for get windows device utilities. + */ +public class WindowsDeviceUtils { + + private static final String COMMA_SEPARATION_PATTERN = ", "; + + public DeviceIDHolder validateDeviceIdentifiers(List deviceIDs, + Message message, MediaType responseMediaType) { + if (deviceIDs == null) { + message.setResponseMessage("Device identifier list is empty"); + throw new BadRequestException(message, responseMediaType); + } + List errorDeviceIdList = new ArrayList(); + List validDeviceIDList = new ArrayList(); + int deviceIDCounter = 0; + + for (String deviceID : deviceIDs) { + deviceIDCounter++; + if (deviceID == null || deviceID.isEmpty()) { + errorDeviceIdList.add(String.format(PluginConstants.DeviceConstants.DEVICE_ID_NOT_FOUND, + deviceIDCounter)); + continue; + } + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceID); + deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes. + MOBILE_DEVICE_TYPE_WINDOWS); + Device device = WindowsAPIUtils.getDeviceManagementService(). + getDevice(deviceIdentifier); + if (device == null || device.getDeviceIdentifier() == null || + device.getDeviceIdentifier().isEmpty()) { + errorDeviceIdList.add(String.format(PluginConstants.DeviceConstants.DEVICE_ID_NOT_FOUND, + deviceIDCounter)); + continue; + } + validDeviceIDList.add(deviceIdentifier); + } catch (DeviceManagementException e) { + errorDeviceIdList.add(String.format(PluginConstants.DeviceConstants.DEVICE_ID_SERVICE_NOT_FOUND, + deviceIDCounter)); + } + } + DeviceIDHolder deviceIDHolder = new DeviceIDHolder(); + deviceIDHolder.setValidDeviceIDList(validDeviceIDList); + deviceIDHolder.setErrorDeviceIdList(errorDeviceIdList); + return deviceIDHolder; + } + + public String convertErrorMapIntoErrorMessage(List errorDeviceIdList) { + return StringUtils.join(errorDeviceIdList.iterator(), COMMA_SEPARATION_PATTERN); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AddTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AddTag.java new file mode 100644 index 000000000..d5adbd9e2 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AddTag.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Configurations that needs to be added on the device. + */ +public class AddTag { + int commandId = -1; + List items; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void buildAddElement(Document doc, Element rootElement) { + if (getItems() != null) { + Element add = doc.createElement(Constants.ADD); + rootElement.appendChild(add); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + add.appendChild(commandId); + } + for (Iterator itemIterator = getItems().iterator(); itemIterator.hasNext(); ) { + Item item = itemIterator.next(); + if (item != null) { + item.buildItemElement(doc, add); + } + } + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Alert.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Alert.java new file mode 100644 index 000000000..0a056669c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Alert.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +/** + * Inform an event occurred from device to server. + */ +public class Alert { + + int commandId = -1; + String data; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public void buildAlertElement(Document doc, Element rootElement) { + Element alert = doc.createElement(Constants.ALERT); + rootElement.appendChild(alert); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + alert.appendChild(commandId); + } + if (getData() != null) { + Element data = doc.createElement(Constants.DATA); + data.appendChild(doc.createTextNode(getData())); + alert.appendChild(data); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AtomicTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AtomicTag.java new file mode 100644 index 000000000..75ad00c03 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AtomicTag.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Wrapper for other SyncML elements. + */ +public class AtomicTag { + int commandId = -1; + List adds; + List replaces; + + public List getReplaces() { + return replaces; + } + + public void setReplaces(List replaces) { + this.replaces = replaces; + } + + public List getAdds() { + return adds; + } + + public void setAdds(List adds) { + this.adds = adds; + } + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public void buildAtomicElement(Document doc, Element rootElement) { + Element atomic = doc.createElement(Constants.ATOMIC); + if (getAdds() != null) { + rootElement.appendChild(atomic); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + atomic.appendChild(commandId); + } + for (Iterator addIterator = getAdds().iterator(); addIterator.hasNext(); ) { + AddTag add = addIterator.next(); + if (add != null) { + add.buildAddElement(doc, atomic); + } + } + } + if (getReplaces() != null) { + for (Iterator replaceIterator = getReplaces().iterator(); replaceIterator.hasNext(); ) { + Replace add = replaceIterator.next(); + if (add != null) { + add.buildReplaceElement(doc, atomic); + } + } + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ChallengeTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ChallengeTag.java new file mode 100644 index 000000000..763032014 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ChallengeTag.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +/** + * Challenge data pass through the device and Device Management server for the security purpose. + */ +public class ChallengeTag { + MetaTag meta; + + public MetaTag getMeta() { + return meta; + } + + public void setMeta(MetaTag meta) { + this.meta = meta; + } + + public void buildChallElement(Document doc, Element rootElement) { + Element chal = doc.createElement(Constants.CHALLENGE); + rootElement.appendChild(chal); + if (getMeta() != null) { + getMeta().buildMetaElement(doc, chal); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Credential.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Credential.java new file mode 100644 index 000000000..a595e5ac8 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Credential.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +/** + * Credentials passed between the device and the server for security purposes. + */ +public class Credential { + MetaTag meta; + String data; + + public MetaTag getMeta() { + return meta; + } + + public void setMeta(MetaTag meta) { + this.meta = meta; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public void buildCredentialElement(Document doc, Element rootElement) { + Element credentials = doc.createElement(Constants.CREDENTIAL); + rootElement.appendChild(credentials); + if (getMeta() != null) { + getMeta().buildMetaElement(doc, credentials); + } + if (getData() != null) { + Element data = doc.createElement(Constants.DATA); + data.appendChild(doc.createTextNode(getData())); + credentials.appendChild(data); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/DeleteTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/DeleteTag.java new file mode 100644 index 000000000..d899240ea --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/DeleteTag.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Configurations that need to be delete on Device. + */ +public class DeleteTag { + int commandId = -1; + List items; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void buildDeleteElement(Document doc, Element rootElement) { + if (getItems() != null) { + Element delete = doc.createElement(Constants.DELETE); + rootElement.appendChild(delete); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + delete.appendChild(commandId); + } + for (Iterator itemIterator = getItems().iterator(); itemIterator.hasNext(); ) { + Item item = itemIterator.next(); + if (item != null) { + item.buildItemElement(doc, delete); + } + } + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ExecuteTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ExecuteTag.java new file mode 100644 index 000000000..90a95924f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ExecuteTag.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Commands that needs to be executed on the device. + */ +public class ExecuteTag { + int commandId = -1; + List items; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void buildExecElement(Document doc, Element rootElement) { + if (getItems() != null) { + Element exec = doc.createElement(Constants.EXECUTE); + rootElement.appendChild(exec); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + exec.appendChild(commandId); + } + for (Iterator itemIterator = getItems().iterator(); itemIterator.hasNext(); ) { + Item item = itemIterator.next(); + if (item != null) { + item.buildItemElement(doc, exec); + } + } + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Get.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Get.java new file mode 100644 index 000000000..6666e329a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Get.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.Iterator; +import java.util.List; + +/** + * Data that needs to be retrieved from the device. + */ +public class Get { + int commandId = -1; + List items; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void buildGetElement(Document doc, Element rootElement) { + if (getItems() != null) { + Element get = doc.createElement(Constants.GET); + rootElement.appendChild(get); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + get.appendChild(commandId); + } + if (getItems() != null) { + for (Iterator itemIterator = getItems().iterator(); itemIterator.hasNext(); ) { + Item item = itemIterator.next(); + if (item != null) { + item.buildItemElement(doc, get); + } + } + } + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Item.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Item.java new file mode 100644 index 000000000..54cf5f65c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Item.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Represents an items that should be retrieved from the device or a command. + */ +public class Item { + + Target target; + Source source; + String data; + MetaTag meta; + + public MetaTag getMeta() { + return meta; + } + + public void setMeta(MetaTag meta) { + this.meta = meta; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public Source getSource() { + return source; + } + + public void setSource(Source source) { + this.source = source; + } + + public Target getTarget() { + return target; + } + + public void setTarget(Target target) { + this.target = target; + } + + public void buildItemElement(Document doc, Element rootElement) { + Element item = doc.createElement(Constants.ITEM); + rootElement.appendChild(item); + + if (getTarget() != null || getSource() != null) { + + if (getTarget() != null) { + getTarget().buildTargetElement(doc, item); + } + if (getSource() != null) { + getSource().buildSourceElement(doc, item); + } + } + if (getData() != null) { + Element data = doc.createElement(Constants.DATA); + data.appendChild(doc.createTextNode(getData())); + item.appendChild(data); + } + if (getMeta() != null) { + getMeta().buildMetaElement(doc, item); + } + + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/MetaTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/MetaTag.java new file mode 100644 index 000000000..fd22b710f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/MetaTag.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +/** + * MetaTag data related to credentials. + */ +public class MetaTag { + + String format; + String type; + String nextNonce; + + public String getNextNonce() { + return nextNonce; + } + + public void setNextNonce(String nextNonce) { + this.nextNonce = nextNonce; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public void buildMetaElement(Document doc, Element rootElement) { + Element meta = doc.createElement(Constants.META); + rootElement.appendChild(meta); + if (getFormat() != null) { + Element format = doc.createElement(Constants.FORMAT); + format.appendChild(doc.createTextNode(getFormat())); + Attr attr = doc.createAttribute(Constants.XMLNS); + attr.setValue(Constants.META_NAMESPACE); + format.setAttributeNode(attr); + meta.appendChild(format); + } + if (getType() != null) { + Element type = doc.createElement(Constants.TYPE); + type.appendChild(doc.createTextNode(getType())); + Attr attr = doc.createAttribute(Constants.XMLNS); + attr.setValue(Constants.META_NAMESPACE); + type.setAttributeNode(attr); + meta.appendChild(type); + } + if (getNextNonce() != null) { + Element nextNonce = doc.createElement(Constants.NEXTNONCE); + nextNonce.appendChild(doc.createTextNode(getNextNonce())); + Attr attr = doc.createAttribute(Constants.XMLNS); + attr.setValue(Constants.META_NAMESPACE); + nextNonce.setAttributeNode(attr); + meta.appendChild(nextNonce); + } + + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Replace.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Replace.java new file mode 100644 index 000000000..4a8058cca --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Replace.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Commands sent from the device. + */ +public class Replace { + int commandId = -1; + List items; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void buildReplaceElement(Document doc, Element rootElement) { + if (getItems() != null) { + Element replace = doc.createElement(Constants.REPLACE); + rootElement.appendChild(replace); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + replace.appendChild(commandId); + } + if (getItems() != null) { + for (Iterator itemIterator = getItems().iterator(); itemIterator.hasNext(); ) { + Item item = itemIterator.next(); + if (item != null) { + item.buildItemElement(doc, replace); + } + } + } + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Results.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Results.java new file mode 100644 index 000000000..a310bd125 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Results.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Results sent for the requests made to the device. + */ +public class Results { + int commandId = -1; + int messageReference = -1; + int commandReference = -1; + List item; + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public int getMessageReference() { + return messageReference; + } + + public void setMessageReference(int messageReference) { + this.messageReference = messageReference; + } + + public int getCommandReference() { + return commandReference; + } + + public void setCommandReference(int commandReference) { + this.commandReference = commandReference; + } + + public List getItem() { + return item; + } + + public void setItem(List item) { + this.item = item; + } + + public void buildResultElement(Document doc, Element rootElement) { + Element results = doc.createElement(Constants.RESULTS); + rootElement.appendChild(results); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + results.appendChild(commandId); + } + if (getMessageReference() != -1) { + Element messageReference = doc.createElement(Constants.MESSAGE_REFERENCE); + messageReference.appendChild(doc.createTextNode(String.valueOf(getMessageReference()))); + results.appendChild(messageReference); + } + if (getCommandReference() != -1) { + Element messageReference = doc.createElement(Constants.COMMAND_REFERENCE); + messageReference.appendChild(doc.createTextNode(String.valueOf(getCommandReference()))); + results.appendChild(messageReference); + } + if (getItem() != null) { + for (Iterator itemIterator = getItem().iterator(); itemIterator.hasNext(); ) { + Item item = itemIterator.next(); + if (item != null) { + item.buildItemElement(doc, results); + } + } + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SequenceTag.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SequenceTag.java new file mode 100644 index 000000000..429512802 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SequenceTag.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Sequence data that use to execute tag list + */ +public class SequenceTag { + + int commandId; + ExecuteTag exec; + Get get; + DeleteTag deleteTag; + AtomicTag atomicTag; + List replaces; + + public DeleteTag getDeleteTag() { + return deleteTag; + } + + public void setDeleteTag(DeleteTag deleteTag) { + this.deleteTag = deleteTag; + } + + public List getReplaces() { + return replaces; + } + + public void setReplaces(List replaces) { + this.replaces = replaces; + } + + public AtomicTag getAtomicTag() { + return atomicTag; + } + + public void setAtomicTag(AtomicTag atomicTag) { + this.atomicTag = atomicTag; + } + + public ExecuteTag getExec() { + return exec; + } + + public void setExec(ExecuteTag exec) { + this.exec = exec; + } + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public Get getGet() { + return get; + } + + public void setGet(Get get) { + this.get = get; + } + + public void buildSequenceElement(Document doc, Element rootElement) { + Element sequence = doc.createElement(Constants.SEQUENCE); + rootElement.appendChild(sequence); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + sequence.appendChild(commandId); + } + if (getExec() != null) { + getExec().buildExecElement(doc, sequence); + } + if (getGet() != null) { + getGet().buildGetElement(doc, sequence); + } + if (getReplaces() != null) { + for (Iterator replaceIterator = getReplaces().iterator(); replaceIterator.hasNext(); ) { + Replace replace = replaceIterator.next(); + if (replace != null) { + replace.buildReplaceElement(doc, sequence); + } + } + } + if (getAtomicTag() != null) { + getAtomicTag().buildAtomicElement(doc, sequence); + } + if (getDeleteTag() != null) { + getDeleteTag().buildDeleteElement(doc, sequence); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Source.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Source.java new file mode 100644 index 000000000..af0f5cbb3 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Source.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Source details of syncml header's. + */ +public class Source { + + private String LocURI; + private String LocName; + + public String getLocURI() { + return LocURI; + } + + public void setLocURI(String locURI) { + LocURI = locURI; + } + + public String getLocName() { + return LocName; + } + + public void setLocName(String locName) { + LocName = locName; + } + + public void buildSourceElement(Document doc, Element rootElement) { + Element target = doc.createElement(Constants.SOURCE); + rootElement.appendChild(target); + if (getLocURI() != null) { + Element locURI = doc.createElement(Constants.LOC_URI); + locURI.appendChild(doc.createTextNode(getLocURI())); + target.appendChild(locURI); + } + if (getLocName() != null) { + Element locName = doc.createElement(Constants.LOC_NAME); + locName.appendChild(doc.createTextNode(getLocName())); + target.appendChild(locName); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Status.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Status.java new file mode 100644 index 000000000..31c209aef --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Status.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Status of a previously sent message to device; + */ +public class Status { + int commandId = -1; + int messageReference = -1; + int commandReference = -1; + String command; + String targetReference; + String data; + ChallengeTag challenge; + + public Status(int commandId, int messageReference, int commandReference, String command, + String targetReference, String data) { + this.commandId = commandId; + this.messageReference = messageReference; + this.commandReference = commandReference; + this.command = command; + this.targetReference = targetReference; + this.data = data; + } + + public Status() { + } + + public ChallengeTag getChallenge() { + return challenge; + } + + public void setChallenge(ChallengeTag challenge) { + this.challenge = challenge; + } + + public String getTargetReference() { + return targetReference; + } + + public void setTargetReference(String targetReference) { + this.targetReference = targetReference; + } + + public int getCommandId() { + return commandId; + } + + public void setCommandId(int commandId) { + this.commandId = commandId; + } + + public int getMessageReference() { + return messageReference; + } + + public void setMessageReference(int messageReference) { + this.messageReference = messageReference; + } + + public int getCommandReference() { + return commandReference; + } + + public void setCommandReference(int commandReference) { + this.commandReference = commandReference; + } + + public String getCommand() { + return command; + } + + public void setCommand(String command) { + this.command = command; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public void buildStatusElement(Document doc, Element rootElement) { + Element status = doc.createElement(Constants.STATUS); + rootElement.appendChild(status); + if (getCommandId() != -1) { + Element commandId = doc.createElement(Constants.COMMAND_ID); + commandId.appendChild(doc.createTextNode(String.valueOf(getCommandId()))); + status.appendChild(commandId); + } + if (getMessageReference() != -1) { + Element msgReference = doc.createElement(Constants.MESSAGE_REFERENCE); + msgReference.appendChild(doc.createTextNode(String.valueOf(getMessageReference()))); + status.appendChild(msgReference); + } + if (getCommandReference() != -1) { + Element commandReference = doc.createElement(Constants.COMMAND_REFERENCE); + commandReference.appendChild(doc.createTextNode(String.valueOf(getCommandReference()))); + status.appendChild(commandReference); + } + if (getCommand() != null) { + Element command = doc.createElement(Constants.COMMAND); + command.appendChild(doc.createTextNode(getCommand())); + status.appendChild(command); + } + if (getTargetReference() != null) { + Element targetReference = doc.createElement(Constants.TARGET_REFERENCE); + targetReference.appendChild(doc.createTextNode(getTargetReference())); + status.appendChild(targetReference); + } + if (getChallenge() != null) { + getChallenge().buildChallElement(doc, status); + } + if (getData() != null) { + Element data = doc.createElement(Constants.DATA); + data.appendChild(doc.createTextNode(getData())); + status.appendChild(data); + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlBody.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlBody.java new file mode 100644 index 000000000..ac132907a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlBody.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; + +import java.util.Iterator; +import java.util.List; + +/** + * Represents the body details of a syncml. + */ +public class SyncmlBody { + Get getCommands; + List exec; + List status; + Alert alert; + Replace replace; + Results results; + SequenceTag sequence; + AtomicTag atomicTag; + + public AtomicTag getAtomicTag() { + return atomicTag; + } + + public void setAtomicTag(AtomicTag atomicTag) { + this.atomicTag = atomicTag; + } + + public SequenceTag getSequence() { + return sequence; + } + + public void setSequence(SequenceTag sequence) { + this.sequence = sequence; + } + + public List getExec() { + return exec; + } + + public void setExec(List exec) { + this.exec = exec; + } + + public Results getResults() { + return results; + } + + public void setResults(Results results) { + this.results = results; + } + + public Replace getReplace() { + return replace; + } + + public void setReplace(Replace replace) { + this.replace = replace; + } + + public List getStatus() { + return status; + } + + public void setStatus(List status) { + this.status = status; + } + + public Alert getAlert() { + return alert; + } + + public void setAlert(Alert alert) { + this.alert = alert; + } + + public Get getGet() { + return getCommands; + } + + public void setGet(Get get) { + this.getCommands = get; + } + + public void buildBodyElement(Document doc, Element rootElement) { + + Element syncBody = doc.createElement(Constants.SYNC_BODY); + rootElement.appendChild(syncBody); + if (getStatus() != null) { + for (int x = 0; x < getStatus().size(); x++) { + if (getStatus().get(x) != null) { + getStatus().get(x).buildStatusElement(doc, syncBody); + } + } + } + if (getAlert() != null) { + getAlert().buildAlertElement(doc, syncBody); + } + if (getResults() != null) { + getResults().buildResultElement(doc, syncBody); + } + if (getGet() != null) { + getGet().buildGetElement(doc, syncBody); + } + if (getReplace() != null) { + getReplace().buildReplaceElement(doc, syncBody); + } + if (getExec() != null) { + for (Iterator execIterator = getExec().iterator(); execIterator.hasNext(); ) { + ExecuteTag exec = execIterator.next(); + if (exec != null) { + exec.buildExecElement(doc, syncBody); + } + } + } + if (getSequence() != null) { + getSequence().buildSequenceElement(doc, syncBody); + } + if (getAtomicTag() != null) { + getAtomicTag().buildAtomicElement(doc, syncBody); + } + syncBody.appendChild(doc.createElement(Constants.FINAL)); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlDocument.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlDocument.java new file mode 100644 index 000000000..284897abe --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlDocument.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Represents a base format of a syncml document + */ +public class SyncmlDocument { + SyncmlHeader header; + SyncmlBody body; + + public SyncmlHeader getHeader() { + return header; + } + + public void setHeader(SyncmlHeader header) { + this.header = header; + } + + public SyncmlBody getBody() { + return body; + } + + public void setBody(SyncmlBody body) { + this.body = body; + } + + public void buildDocument(Document doc, Element rootElement) { + if (getHeader() != null) { + getHeader().buildSyncmlHeaderElement(doc, rootElement); + } + if (getBody() != null) { + getBody().buildBodyElement(doc, rootElement); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlHeader.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlHeader.java new file mode 100644 index 000000000..e0fc9deab --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlHeader.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Represents the header details of a syncml. + */ +public class SyncmlHeader { + private int sessionId = -1; + private int MsgID = -1; + private Target target; + private Source source; + private Credential credential; + private String hexadecimalSessionId; + + public String getHexadecimalSessionId() { + return hexadecimalSessionId; + } + + public void setHexadecimalSessionId(String hexSessionId) { + this.hexadecimalSessionId = hexSessionId; + } + + public Credential getCredential() { + return credential; + } + + public void setCredential(Credential credential) { + this.credential = credential; + } + + public int getSessionId() { + return sessionId; + } + + public void setSessionId(int sessionId) { + this.sessionId = sessionId; + } + + public int getMsgID() { + return MsgID; + } + + public void setMsgID(int msgID) { + this.MsgID = msgID; + } + + public Target getTarget() { + return target; + } + + public void setTarget(Target target) { + this.target = target; + } + + public Source getSource() { + return source; + } + + public void setSource(Source source) { + this.source = source; + } + + public void buildSyncmlHeaderElement(Document doc, Element rootElement) { + Element syncHdr = doc.createElement(Constants.SYNC_HDR); + rootElement.appendChild(syncHdr); + Element verDTD = doc.createElement(Constants.VER_DTD); + verDTD.appendChild(doc.createTextNode(Constants.VER_DTD_VALUE)); + syncHdr.appendChild(verDTD); + + Element verProtocol = doc.createElement(Constants.VER_PROTOCOL); + verProtocol.appendChild(doc.createTextNode(Constants.VER_PROTOCOL_VALUE)); + syncHdr.appendChild(verProtocol); + if (getHexadecimalSessionId() != null) { + Element sessionId = doc.createElement(Constants.SESSION_ID); + sessionId.appendChild(doc.createTextNode(getHexadecimalSessionId())); + syncHdr.appendChild(sessionId); + } + if (getMsgID() != -1) { + Element msgId = doc.createElement(Constants.MESSAGE_ID); + msgId.appendChild(doc.createTextNode(String.valueOf(getMsgID()))); + syncHdr.appendChild(msgId); + } + if (getTarget() != null) { + getTarget().buildTargetElement(doc, syncHdr); + } + if (getSource() != null) { + getSource().buildSourceElement(doc, syncHdr); + } + if (getCredential() != null) { + getCredential().buildCredentialElement(doc, syncHdr); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Target.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Target.java new file mode 100644 index 000000000..03efb3ee1 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Target.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Target details of syncml header's. + */ +public class Target { + + private String LocURI; + private String LocName; + + public String getLocURI() { + return LocURI; + } + + public void setLocURI(String locURI) { + LocURI = locURI; + } + + public String getLocName() { + return LocName; + } + + public void setLocName(String locName) { + LocName = locName; + } + + public void buildTargetElement(Document doc, Element rootElement) { + Element target = doc.createElement(Constants.TARGET); + rootElement.appendChild(target); + if (getLocURI() != null) { + Element locURI = doc.createElement(Constants.LOC_URI); + locURI.appendChild(doc.createTextNode(getLocURI())); + target.appendChild(locURI); + } + if (getLocName() != null) { + Element locName = doc.createElement(Constants.LOC_NAME); + locName.appendChild(doc.createTextNode(getLocName())); + target.appendChild(locName); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/WindowsOperationException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/WindowsOperationException.java new file mode 100644 index 000000000..d4202f660 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/WindowsOperationException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations; + +/** + * Exceptions related to operation retrieval and syncml generation + */ +public class WindowsOperationException extends Exception { + + private static final long serialVersionUID = 5435636243242623629L; + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public WindowsOperationException(String errorMessage) { + super(errorMessage); + } + + public WindowsOperationException(String errorMessage, Throwable throwable) { + super(errorMessage, throwable); + setErrorMessage(errorMessage); + } + + public WindowsOperationException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public WindowsOperationException() { + super(); + } + + public WindowsOperationException(Throwable throwable) { + super(throwable); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/Constants.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/Constants.java new file mode 100644 index 000000000..6c4443165 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/Constants.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +/** + * Constant values used in syncml generator. + */ +public class Constants { + + public static final String PROVIDER_ID = "MobiCDMServer"; + public static final String SERVER_SECRET = "dummy"; + public static final String INITIAL_NONCE = "ZHVtbXk="; + public static final String DISENROLL_ALERT_DATA = "1226"; + public static final String INITIAL_ALERT_DATA = "1201"; + public static final int EMPTY = 0; + + public static final String SYNCML_ROOT_ELEMENT_NAME = "SyncML"; + public static final String XMLNS_SYNCML = "SYNCML:SYNCML1.2"; + public static final String UTF_8 = "UTF-8"; + public static final String MD5 = "MD5"; + public static final String YES = "yes"; + public static final String ERROR = "Error"; + public static final String INFORMATION = "information"; + + public static final String EXECUTE = "Exec"; + public static final String ATOMIC = "Atomic"; + public static final String ADD = "Add"; + public static final String COMMAND_ID = "CmdID"; + public static final String GET = "Get"; + public static final String DELETE = "Delete"; + public static final String ITEM = "Item"; + public static final String SOURCE = "Source"; + public static final String LOC_URI = "LocURI"; + public static final String LOC_NAME = "LocName"; + public static final String MESSAGE_REFERENCE = "MsgRef"; + public static final String COMMAND_REFERENCE = "CmdRef"; + public static final String COMMAND = "Cmd"; + public static final String TARGET_REFERENCE = "TargetRef"; + public static final String DATA = "Data"; + public static final String STATUS = "Status"; + public static final String SYNC_BODY = "SyncBody"; + public static final String SYNC_HDR = "SyncHdr"; + public static final String VER_DTD = "VerDTD"; + public static final String VER_PROTOCOL = "VerProto"; + public static final String SESSION_ID = "SessionID"; + public static final String MESSAGE_ID = "MsgID"; + public static final String TARGET = "Target"; + public static final String VER_DTD_VALUE = "1.2"; + public static final String VER_PROTOCOL_VALUE = "DM/1.2"; + public static final String ALERT = "Alert"; + public static final String FINAL = "Final"; + public static final String REPLACE = "Replace"; + public static final String META = "Meta"; + public static final String CREDENTIAL = "Cred"; + public static final String FORMAT = "Format"; + public static final String TYPE = "Type"; + public static final String NEXTNONCE = "NextNonce"; + public static final String CHALLENGE = "chal"; + public static final String META_NAMESPACE = "syncml:metinf"; + public static final String XMLNS = "xmlns"; + public static final String RESULTS = "Results"; + public static final String CRED_FORMAT = "b64"; + public static final String CRED_TYPE = "syncml:auth-md5"; + public static final String SEQUENCE = "Sequence"; + public static final String META_FORMAT_INT = "int"; + public static final String META_FORMAT_CHARACTER = "chr"; + + /** + * SynclML service related constants + */ + public final class SyncMLResponseCodes { + public static final String AUTHENTICATION_ACCEPTED = "212"; + public static final String ACCEPTED = "200"; + public static final String ACCEPTED_FOR_PROCESSING = "202"; + public static final String PIN_NOTFOUND = "405"; + public static final String CREDENTIALS_MISSING = "407"; + public static final String INVALID_CREDENTIALS = "401"; + public static final String LOCKRESET_NOTIFICATION = "Error occurred in Device Lock Operation. " + + "Please trigger lock-reset operation."; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/DeviceInfo.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/DeviceInfo.java new file mode 100644 index 000000000..052ff48e2 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/DeviceInfo.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class generate Info type operation list. + */ +public class DeviceInfo { + public List getDeviceInfo() { + + List deviceInfoOperations = new ArrayList<>(); + + Operation osVersion = new Operation(); + osVersion.setCode(PluginConstants.SyncML.SOFTWARE_VERSION); + osVersion.setType(Operation.Type.INFO); + deviceInfoOperations.add(osVersion); + + Operation imsi = new Operation(); + imsi.setCode(PluginConstants.SyncML.IMSI); + imsi.setType(Operation.Type.INFO); + deviceInfoOperations.add(imsi); + + Operation imei = new Operation(); + imei.setCode(PluginConstants.SyncML.IMEI); + imei.setType(Operation.Type.INFO); + deviceInfoOperations.add(imei); + + Operation deviceID = new Operation(); + deviceID.setCode(PluginConstants.SyncML.DEV_ID); + deviceID.setType(Operation.Type.INFO); + deviceInfoOperations.add(deviceID); + + Operation manufacturer = new Operation(); + manufacturer.setCode(PluginConstants.SyncML.MANUFACTURER); + manufacturer.setType(Operation.Type.INFO); + deviceInfoOperations.add(manufacturer); + + Operation model = new Operation(); + model.setCode(PluginConstants.SyncML.MODEL); + model.setType(Operation.Type.INFO); + deviceInfoOperations.add(model); + + Operation language = new Operation(); + language.setCode(PluginConstants.SyncML.LANGUAGE); + language.setType(Operation.Type.INFO); + deviceInfoOperations.add(language); + + Operation vendor = new Operation(); + vendor.setCode(PluginConstants.SyncML.VENDOR); + vendor.setType(Operation.Type.INFO); + deviceInfoOperations.add(vendor); + + Operation macaddress = new Operation(); + macaddress.setCode(PluginConstants.SyncML.MAC_ADDRESS); + macaddress.setType(Operation.Type.INFO); + deviceInfoOperations.add(macaddress); + + Operation resolution = new Operation(); + resolution.setCode(PluginConstants.SyncML.RESOLUTION); + resolution.setType(Operation.Type.INFO); + deviceInfoOperations.add(resolution); + + Operation deviceName = new Operation(); + deviceName.setCode(PluginConstants.SyncML.DEVICE_NAME); + deviceName.setType(Operation.Type.INFO); + deviceInfoOperations.add(deviceName); + + return deviceInfoOperations; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationCode.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationCode.java new file mode 100644 index 000000000..c586cf619 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationCode.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +/** + * Maps operation codes to device specific format. + */ +public class OperationCode { + public static enum Info { + DEV_ID("./DevInfo/DevId"), + MANUFACTURER("./DevInfo/Man"), + DEVICE_MODEL("./DevInfo/Mod"), + DM_VERSION("./DevInfo/DmV"), + LANGUAGE("./DevInfo/Lang"), + IMSI("./Vendor/MSFT/DeviceInstanceService/Identity/Identity1/IMSI"), + IMEI("./Vendor/MSFT/DeviceInstanceService/Identity/Identity1/IMEI"), + SOFTWARE_VERSION("./DevDetail/SwV"), + VENDER("./DevDetail/OEM"), + MAC_ADDRESS("./DevDetail/Ext/WLANMACAddress"), + RESOLUTION("./DevDetail/Ext/Microsoft/Resolution"), + DEVICE_NAME("./DevDetail/Ext/Microsoft/DeviceName"), + CHANNEL_URI("./Vendor/MSFT/DMClient/Provider/MobiCDMServer/Push/ChannelURI"), + LOCK_PIN("./Vendor/MSFT/RemoteLock/NewPINValue"), + LOCK_RESET("./Vendor/MSFT/RemoteLock/LockAndResetPIN"), + CAMERA("./Vendor/MSFT/PolicyManager/My/Camera/AllowCamera"), + CAMERA_STATUS("./Vendor/MSFT/PolicyManager/Device/Camera/AllowCamera"), + ENCRYPT_STORAGE_STATUS("./Vendor/MSFT/PolicyManager/Device/Security/RequireDeviceEncryption"), + DEVICE_PASSWORD_STATUS("./Vendor/MSFT/PolicyManager/Device/DeviceLock/DevicePasswordEnabled"), + DEVICE_PASSCODE_DELETE("./Vendor/MSFT/PolicyManager/My/DeviceLock"), + LONGITUDE("./Vendor/MSFT/RemoteFind/Location/Longitude"), + LATITUDE("./Vendor/MSFT/RemoteFind/Location/Latitude"); + + private final String code; + + Info(String code) { + this.code = code; + } + + public String getCode() { + return this.code; + } + + } + + public static enum Command { + DEVICE_RING("./Vendor/MSFT/RemoteRing/Ring"), + DEVICE_LOCK("./Vendor/MSFT/RemoteLock/Lock"), + WIPE_DATA("./Vendor/MSFT/RemoteWipe/doWipe"), + DISENROLL("./Vendor/MSFT/DMClient/Unenroll"), + LOCK_RESET("./Vendor/MSFT/RemoteLock/LockAndResetPIN"), + CAMERA("./Vendor/MSFT/PolicyManager/My/Camera/AllowCamera"), + ENCRYPT_STORAGE("./Vendor/MSFT/PolicyManager/My/Security/RequireDeviceEncryption"), + CAMERA_STATUS("./Vendor/MSFT/PolicyManager/Device/Camera/AllowCamera"), + ENCRYPT_STORAGE_STATUS("./Vendor/MSFT/PolicyManager/Device/Security/RequireDeviceEncryption"), + DEVICE_PASSWORD_ENABLE("./Vendor/MSFT/PolicyManager/My/DeviceLock/DevicePasswordEnabled"); + + private final String code; + + Command(String code) { + this.code = code; + } + + public String getCode() { + return this.code; + } + + } + + public static enum Configure { + WIFI("./Vendor/MSFT/WiFi/Profile/MyNetwork/WlanXml"), + CAMERA("./Vendor/MSFT/PolicyManager/My/Camera/AllowCamera"), + CAMERA_STATUS("./Vendor/MSFT/PolicyManager/Device/Camera/AllowCamera"), + ENCRYPT_STORAGE("./Vendor/MSFT/PolicyManager/My/Security/RequireDeviceEncryption"), + ENCRYPT_STORAGE_STATUS("./Vendor/MSFT/PolicyManager/Device/Security/RequireDeviceEncryption"), + PASSWORD_MAX_FAIL_ATTEMPTS("./Vendor/MSFT/PolicyManager/My/DeviceLock/MaxDevicePasswordFailedAttempts"), + DEVICE_PASSWORD_ENABLE("./Vendor/MSFT/PolicyManager/My/DeviceLock/DevicePasswordEnabled"), + SIMPLE_PASSWORD("./Vendor/MSFT/PolicyManager/My/DeviceLock/AllowSimpleDevicePassword"), + MIN_PASSWORD_LENGTH("./Vendor/MSFT/PolicyManager/My/DeviceLock/MinDevicePasswordLength"), + Alphanumeric_PASSWORD("./Vendor/MSFT/PolicyManager/My/DeviceLock/AlphanumericDevicePasswordRequired"), + PASSWORD_EXPIRE("./Vendor/MSFT/PolicyManager/My/DeviceLock/DevicePasswordExpiration"), + PASSWORD_HISTORY("./Vendor/MSFT/PolicyManager/My/DeviceLock/DevicePasswordHistory"), + MAX_PASSWORD_INACTIVE_TIME("./Vendor/MSFT/PolicyManager/My/DeviceLock/MaxInactivityTimeDeviceLock"), + MIN_PASSWORD_COMPLEX_CHARACTERS("./Vendor/MSFT/PolicyManager/My/DeviceLock/MinDevicePasswordComplexCharacters"); + + private final String code; + + Configure(String code) { + this.code = code; + } + + public String getCode() { + return this.code; + } + + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationReply.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationReply.java new file mode 100644 index 000000000..289bf3a94 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationReply.java @@ -0,0 +1,772 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +import com.google.gson.Gson; +import org.json.JSONException; +import org.json.JSONObject; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.SyncmlCommandType; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlMessageFormatException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlOperationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.mdm.mobileservices.windows.operations.*; +import org.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans.PasscodePolicy; +import org.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans.Wifi; +import org.wso2.carbon.policy.mgt.common.FeatureManagementException; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.common.ProfileFeature; + +import java.util.ArrayList; +import java.util.List; + +import static org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils.convertToDeviceIdentifierObject; +import static org.wso2.carbon.mdm.mobileservices.windows.operations.util.OperationCode.*; + +/** + * Used to generate a reply to a receiving syncml from a device. + */ +public class OperationReply { + + private SyncmlDocument syncmlDocument; + private SyncmlDocument replySyncmlDocument; + private int headerCommandId = 1; + private static final int HEADER_STATUS_ID = 0; + private static final String RESULTS_COMMAND_TEXT = "Results"; + private static final String HEADER_COMMAND_TEXT = "SyncHdr"; + private static final String ALERT_COMMAND_TEXT = "Alert"; + private static final String REPLACE_COMMAND_TEXT = "Replace"; + private static final String GET_COMMAND_TEXT = "Get"; + private static final String EXEC_COMMAND_TEXT = "Exec"; + private List operations; + Gson gson = new Gson(); + + public OperationReply(SyncmlDocument syncmlDocument, List operations) { + this.syncmlDocument = syncmlDocument; + replySyncmlDocument = new SyncmlDocument(); + this.operations = operations; + } + + public OperationReply(SyncmlDocument syncmlDocument) { + this.syncmlDocument = syncmlDocument; + replySyncmlDocument = new SyncmlDocument(); + } + + public SyncmlDocument generateReply() throws SyncmlMessageFormatException, SyncmlOperationException { + generateHeader(); + generateBody(); + return replySyncmlDocument; + } + + private void generateHeader() throws SyncmlMessageFormatException { + String nextnonceValue = Constants.INITIAL_NONCE; + SyncmlHeader sourceHeader = syncmlDocument.getHeader(); + SyncmlHeader header = new SyncmlHeader(); + header.setMsgID(sourceHeader.getMsgID()); + header.setHexadecimalSessionId(Integer.toHexString(sourceHeader.getSessionId())); + Target target = new Target(); + target.setLocURI(sourceHeader.getSource().getLocURI()); + header.setTarget(target); + + Source source = new Source(); + source.setLocURI(sourceHeader.getTarget().getLocURI()); + header.setSource(source); + + Credential cred = new Credential(); + if (sourceHeader.getCredential() == null) { + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.CRED_FORMAT); + meta.setType(Constants.CRED_TYPE); + cred.setMeta(meta); + } else { + cred.setMeta(sourceHeader.getCredential().getMeta()); + } + SyncmlBody sourcebody = syncmlDocument.getBody(); + List statuses = sourcebody.getStatus(); + + for (Status status : statuses) { + if (HEADER_COMMAND_TEXT.equals(status.getCommand()) && + status.getChallenge() != null) { + nextnonceValue = status.getChallenge().getMeta().getNextNonce(); + } + } + cred.setData(new SyncmlCredentials().generateCredData(nextnonceValue)); + header.setCredential(cred); + + replySyncmlDocument.setHeader(header); + } + + private void generateBody() throws SyncmlMessageFormatException, SyncmlOperationException { + SyncmlBody syncmlBody = generateStatuses(); + try { + appendOperations(syncmlBody); + } catch (PolicyManagementException e) { + throw new SyncmlOperationException("Error occurred while retrieving policy operations.", e); + } catch (FeatureManagementException e) { + throw new SyncmlOperationException("Error occurred while retrieving effective policy operations.", e); + } catch (JSONException e) { + throw new SyncmlMessageFormatException("Error Occurred while parsing operation object.", e); + } + replySyncmlDocument.setBody(syncmlBody); + } + + private SyncmlBody generateStatuses() { + SyncmlBody sourceSyncmlBody = syncmlDocument.getBody(); + SyncmlHeader sourceHeader = syncmlDocument.getHeader(); + Status headerStatus; + SyncmlBody syncmlBodyReply = new SyncmlBody(); + List statuses = new ArrayList<>(); + List sourceStatuses = sourceSyncmlBody.getStatus(); + if (sourceStatuses.isEmpty()) { + headerStatus = + new Status(headerCommandId, sourceHeader.getMsgID(), HEADER_STATUS_ID, + HEADER_COMMAND_TEXT, sourceHeader.getSource().getLocURI(), + String.valueOf(Constants.SyncMLResponseCodes.AUTHENTICATION_ACCEPTED)); + statuses.add(headerStatus); + } else { + for (Status sourceStatus : sourceStatuses) { + if (sourceStatus.getChallenge() != null && HEADER_COMMAND_TEXT.equals(sourceStatus.getCommand())) { + + headerStatus = + new Status(headerCommandId, sourceHeader.getMsgID(), HEADER_STATUS_ID, + HEADER_COMMAND_TEXT, sourceHeader.getSource().getLocURI(), + String.valueOf(Constants.SyncMLResponseCodes.AUTHENTICATION_ACCEPTED)); + statuses.add(headerStatus); + } + } + } + if (sourceSyncmlBody.getResults() != null) { + int ResultCommandId = ++headerCommandId; + Status resultStatus = new Status(ResultCommandId, sourceHeader.getMsgID(), + sourceSyncmlBody.getResults().getCommandId(), RESULTS_COMMAND_TEXT, null, + String.valueOf(Constants.SyncMLResponseCodes.ACCEPTED)); + statuses.add(resultStatus); + } + if (sourceSyncmlBody.getAlert() != null) { + int alertCommandId = ++headerCommandId; + Status alertStatus = new Status(alertCommandId, + sourceHeader.getMsgID(), + sourceSyncmlBody.getAlert().getCommandId(), + ALERT_COMMAND_TEXT, null, + String.valueOf(Constants.SyncMLResponseCodes.ACCEPTED)); + statuses.add(alertStatus); + } + if (sourceSyncmlBody.getReplace() != null) { + int replaceCommandId = ++headerCommandId; + Status replaceStatus = new Status(replaceCommandId, sourceHeader.getMsgID(), + sourceSyncmlBody.getReplace().getCommandId(), REPLACE_COMMAND_TEXT, null, + String.valueOf(Constants.SyncMLResponseCodes.ACCEPTED) + ); + statuses.add(replaceStatus); + } + if (sourceSyncmlBody.getExec() != null) { + List Executes = sourceSyncmlBody.getExec(); + for (ExecuteTag exec : Executes) { + int execCommandId = ++headerCommandId; + Status execStatus = new Status(execCommandId, sourceHeader.getMsgID(), + exec.getCommandId(), EXEC_COMMAND_TEXT, null, String.valueOf( + Constants.SyncMLResponseCodes.ACCEPTED)); + statuses.add(execStatus); + } + } + if (sourceSyncmlBody.getGet() != null) { + int getCommandId = ++headerCommandId; + Status execStatus = new Status(getCommandId, sourceHeader.getMsgID(), sourceSyncmlBody + .getGet().getCommandId(), GET_COMMAND_TEXT, null, String.valueOf( + Constants.SyncMLResponseCodes.ACCEPTED)); + statuses.add(execStatus); + } + syncmlBodyReply.setStatus(statuses); + return syncmlBodyReply; + } + + private void appendOperations(SyncmlBody syncmlBody) throws PolicyManagementException, + FeatureManagementException, JSONException, SyncmlOperationException { + Get getElement = new Get(); + List getElements = new ArrayList<>(); + List executeElements = new ArrayList<>(); + AtomicTag atomicTagElement = new AtomicTag(); + List addElements = new ArrayList<>(); + Replace replaceElement = new Replace(); + List replaceItems = new ArrayList<>(); + SequenceTag monitorSequence = new SequenceTag(); + + if (operations != null) { + for (Operation operation : operations) { + Operation.Type type = operation.getType(); + switch (type) { + case POLICY: + if (this.syncmlDocument.getBody().getAlert() != null) { + if (this.syncmlDocument.getBody().getAlert().getData().equals + (Constants.INITIAL_ALERT_DATA)) { + SequenceTag policySequence = new SequenceTag(); + policySequence = buildSequence(operation, policySequence); + syncmlBody.setSequence(policySequence); + } + } + break; + case CONFIG: + List addConfigurations = appendAddConfiguration(operation); + for (AddTag addConfiguration : addConfigurations) { + addElements.add(addConfiguration); + } + break; + case MESSAGE: + + break; + case INFO: + Item itemGet = appendGetInfo(operation); + getElements.add(itemGet); + break; + case COMMAND: + if (operation.getCode().equals(PluginConstants + .OperationCodes.DEVICE_LOCK)) { + ExecuteTag execElement = executeCommand(operation); + executeElements.add(execElement); + } + if (operation.getCode().equals(PluginConstants + .OperationCodes.DEVICE_RING)) { + ExecuteTag execElement = executeCommand(operation); + executeElements.add(execElement); + } + if (operation.getCode().equals(PluginConstants + .OperationCodes.DISENROLL)) { + ExecuteTag execElement = executeCommand(operation); + executeElements.add(execElement); + } + if (operation.getCode().equals(PluginConstants + .OperationCodes.WIPE_DATA)) { + ExecuteTag execElement = executeCommand(operation); + executeElements.add(execElement); + } + if (operation.getCode().equals(PluginConstants + .OperationCodes.LOCK_RESET)) { + SequenceTag sequenceElement = new SequenceTag(); + SequenceTag sequence = buildSequence(operation, sequenceElement); + syncmlBody.setSequence(sequence); + } + if (operation.getCode().equals(PluginConstants + .OperationCodes.MONITOR)) { + + Get monitorGetElement = new Get(); + List monitorItems; + List profileFeatures; + + if (this.syncmlDocument.getBody().getAlert() != null) { + if (this.syncmlDocument.getBody().getAlert().getData().equals + (Constants.INITIAL_ALERT_DATA)) { + + monitorSequence.setCommandId(operation.getId()); + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject( + syncmlDocument.getHeader().getSource().getLocURI()); + try { + profileFeatures = WindowsAPIUtils.getPolicyManagerService(). + getEffectiveFeatures(deviceIdentifier); + } catch (FeatureManagementException e) { + throw new SyncmlOperationException("Error in getting effective policy.", e); + } + monitorItems = buildMonitorOperation(profileFeatures); + if (!monitorItems.isEmpty()) { + monitorGetElement.setCommandId(operation.getId()); + monitorGetElement.setItems(monitorItems); + } + monitorSequence.setGet(monitorGetElement); + syncmlBody.setSequence(monitorSequence); + } + } + } + break; + } + } + } + if (!replaceItems.isEmpty()) { + replaceElement.setCommandId(300); + replaceElement.setItems(replaceItems); + } + if (!getElements.isEmpty()) { + getElement.setCommandId(75); + getElement.setItems(getElements); + } + if (!addElements.isEmpty()) { + atomicTagElement.setCommandId(400); + atomicTagElement.setAdds(addElements); + } + syncmlBody.setGet(getElement); + syncmlBody.setExec(executeElements); + syncmlBody.setAtomicTag(atomicTagElement); + syncmlBody.setReplace(replaceElement); + } + + private Item appendExecInfo(Operation operation) { + Item item = new Item(); + String operationCode = operation.getCode(); + for (Command command : Command.values()) { + if (operationCode != null && operationCode.equals(command.name())) { + Target target = new Target(); + target.setLocURI(command.getCode()); + if (operation.getCode().equals(PluginConstants + .OperationCodes.DISENROLL)) { + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_CHARACTER); + item.setMeta(meta); + item.setData(Constants.PROVIDER_ID); + } + item.setTarget(target); + } + } + return item; + } + + private Item appendGetInfo(Operation operation) { + Item item = new Item(); + String operationCode = operation.getCode(); + for (Info info : Info.values()) { + if (operationCode != null && operationCode.equals(info.name())) { + Target target = new Target(); + target.setLocURI(info.getCode()); + item.setTarget(target); + } + } + if ((operationCode != null) && operationCode.equals( + PluginConstants.OperationCodes.LOCK_RESET)) { + operation.setCode(PluginConstants.OperationCodes.PIN_CODE); + for (Info getInfo : Info.values()) { + if (operation.getCode().equals(getInfo.name())) { + Target target = new Target(); + target.setLocURI(getInfo.getCode()); + item.setTarget(target); + } + } + } + return item; + } + + private Item appendReplaceInfo(Operation operation) throws JSONException { + String policyAllowData = "1"; + String policyDisallowData = "0"; + Item item = new Item(); + Target target = new Target(); + String operationCode = operation.getCode(); + JSONObject payload = new JSONObject(operation.getPayLoad().toString()); + for (Command command : Command.values()) { + + if (operationCode != null && operationCode.equals(command.name())) { + target.setLocURI(command.getCode()); + + if (operation.getCode().equals(PluginConstants + .OperationCodes.CAMERA)) { + + if (payload.getBoolean("enabled")) { + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_INT); + item.setTarget(target); + item.setMeta(meta); + item.setData(policyAllowData); + } else { + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_INT); + item.setTarget(target); + item.setMeta(meta); + item.setData(policyDisallowData); + } + } + if (operation.getCode().equals(PluginConstants + .OperationCodes.ENCRYPT_STORAGE)) { + + if (payload.getBoolean("encrypted")) { + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_INT); + item.setTarget(target); + item.setMeta(meta); + item.setData(policyAllowData); + } else { + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_INT); + item.setTarget(target); + item.setMeta(meta); + item.setData(policyDisallowData); + } + } + } + } + return item; + } + + private List appendAddInfo(Operation operation) throws WindowsOperationException { + + List addList = new ArrayList<>(); + Gson gson = new Gson(); + + if (operation.getCode().equals(PluginConstants.OperationCodes.PASSCODE_POLICY)) { + + PasscodePolicy passcodeObject = gson.fromJson((String) operation.getPayLoad(), PasscodePolicy.class); + + for (Configure configure : Configure.values()) { + + if (operation.getCode() != null && PluginConstants.OperationCodes.PASSWORD_MAX_FAIL_ATTEMPTS. + equals(configure.name())) { + AddTag add = generatePasscodePolicyData(configure, passcodeObject.getMaxFailedAttempts()); + addList.add(add); + } + if (operation.getCode() != null && (PluginConstants.OperationCodes.DEVICE_PASSWORD_ENABLE. + equals(configure.name()) || PluginConstants.OperationCodes.SIMPLE_PASSWORD. + equals(configure.name()) || PluginConstants.OperationCodes.ALPHANUMERIC_PASSWORD. + equals(configure.name()))) { + AddTag add = generatePasscodeBooleanData(operation, configure); + addList.add(add); + } + if (operation.getCode() != null && PluginConstants.OperationCodes.MIN_PASSWORD_LENGTH. + equals(configure.name())) { + AddTag add = generatePasscodePolicyData(configure, passcodeObject.getMinLength()); + addList.add(add); + } + if (operation.getCode() != null && PluginConstants.OperationCodes.PASSWORD_EXPIRE. + equals(configure.name())) { + AddTag add = generatePasscodePolicyData(configure, passcodeObject.getMaxPINAgeInDays()); + addList.add(add); + } + if (operation.getCode() != null && PluginConstants.OperationCodes.PASSWORD_HISTORY. + equals(configure.name())) { + int pinHistory = passcodeObject.getPinHistory(); + AddTag add = generatePasscodePolicyData(configure, pinHistory); + addList.add(add); + } + if (operation.getCode() != null && PluginConstants.OperationCodes.MAX_PASSWORD_INACTIVE_TIME. + equals(configure.name())) { + AddTag add = generatePasscodePolicyData(configure, passcodeObject.getMaxInactiveTime()); + addList.add(add); + } + if (operation.getCode() != null && PluginConstants.OperationCodes.MIN_PASSWORD_COMPLEX_CHARACTERS. + equals(configure.name())) { + int complexChars = passcodeObject.getMinComplexChars(); + AddTag add = generatePasscodePolicyData(configure, complexChars); + addList.add(add); + } + } + } + return addList; + } + + private List appendAddConfiguration(Operation operation) { + + List addList = new ArrayList<>(); + Gson gson = new Gson(); + + if (SyncmlCommandType.WIFI.getValue().equals(operation.getCode())) { + AddTag add = new AddTag(); + String operationCode = operation.getCode(); + Wifi wifiObject = gson.fromJson((String) operation.getPayLoad(), Wifi.class); + String data = "<?xml version="1.0"?><WLANProfile" + + "xmlns="http://www.microsoft.com/networking/WLAN/profile/v1"><name>" + + wifiObject.getNetworkName() + "</name><SSIDConfig><SSID><name>" + + wifiObject.getSsid() + "</name></SSID></SSIDConfig><connectionType>" + + wifiObject.getConnectionType() + "</connectionType><connectionMode>" + + wifiObject.getConnectionMode() + "</connectionMode><MSM><security><" + + "authEncryption><authentication>" + wifiObject.getAuthentication() + + "</authentication><encryption>" + wifiObject.getEncryption() + + "</encryption></authEncryption><sharedKey><keyType>" + + wifiObject.getKeyType() + "</keyType><protected>" + wifiObject.getProtection() + + "</protected><keyMaterial>" + wifiObject.getKeyMaterial() + + "</keyMaterial></sharedKey></security></MSM></WLANProfile>"; + + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_CHARACTER); + List items = new ArrayList<>(); + + for (Configure configure : Configure.values()) { + if (operationCode != null && operationCode.equals(configure.name())) { + Target target = new Target(); + target.setLocURI(configure.getCode()); + items.get(0).setTarget(target); + } + } + items.get(0).setMeta(meta); + items.get(0).setData(data); + + add.setCommandId(301); + add.setItems(items); + addList.add(add); + return addList; + } + return null; + } + + public ExecuteTag executeCommand(Operation operation) { + ExecuteTag execElement = new ExecuteTag(); + execElement.setCommandId(operation.getId()); + List itemsExec = new ArrayList<>(); + Item itemExec = appendExecInfo(operation); + itemsExec.add(itemExec); + execElement.setItems(itemsExec); + return execElement; + } + + public SequenceTag buildSequence(Operation operation, SequenceTag sequenceElement) throws + JSONException, SyncmlOperationException { + + sequenceElement.setCommandId(operation.getId()); + List replaceItems = new ArrayList<>(); + + if (operation.getCode().equals(PluginConstants.OperationCodes.LOCK_RESET)) { + ExecuteTag execElement = executeCommand(operation); + Get getElements = new Get(); + getElements.setCommandId(operation.getId()); + List getItems = new ArrayList<>(); + Item itemGets = appendGetInfo(operation); + getItems.add(itemGets); + getElements.setItems(getItems); + + sequenceElement.setExec(execElement); + sequenceElement.setGet(getElements); + return sequenceElement; + + } else if (operation.getCode().equals(PluginConstants.OperationCodes.POLICY_BUNDLE)) { + List policyOperations; + try { + policyOperations = (List) operation.getPayLoad(); + } catch (ClassCastException e) { + throw new ClassCastException(); + } + for (Operation policy : policyOperations) { + if (policy.getCode().equals(PluginConstants.OperationCodes.CAMERA)) { + Replace replaceCameraConfig = new Replace(); + Item cameraItem; + List cameraItems = new ArrayList<>(); + try { + cameraItem = appendReplaceInfo(policy); + cameraItems.add(cameraItem); + } catch (JSONException e) { + throw new SyncmlOperationException("Error occurred while parsing payload object to json.", e); + } + replaceCameraConfig.setCommandId(operation.getId()); + replaceCameraConfig.setItems(cameraItems); + replaceItems.add(replaceCameraConfig); + } + if (policy.getCode().equals(PluginConstants.OperationCodes.ENCRYPT_STORAGE)) { + + Replace replaceStorageConfig = new Replace(); + Item storageItem; + List storageItems = new ArrayList<>(); + try { + storageItem = appendReplaceInfo(policy); + storageItems.add(storageItem); + } catch (JSONException e) { + throw new SyncmlOperationException("Error occurred while parsing payload object to json.", e); + } + replaceStorageConfig.setCommandId(operation.getId()); + replaceStorageConfig.setItems(storageItems); + replaceItems.add(replaceStorageConfig); + + } + if (policy.getCode().equals(PluginConstants.OperationCodes.PASSCODE_POLICY)) { + AtomicTag atomicTagElement = new AtomicTag(); + List addConfig; + try { + addConfig = appendAddInfo(policy); + atomicTagElement.setAdds(addConfig); + atomicTagElement.setCommandId(operation.getId()); + + sequenceElement.setAtomicTag(atomicTagElement); + } catch (WindowsOperationException e) { + throw new SyncmlOperationException("Error occurred while generating operation payload.", e); + } + } + } + if (!replaceItems.isEmpty()) { + sequenceElement.setReplaces(replaceItems); + } + return sequenceElement; + + } else { + return null; + } + } + + public List buildMonitorOperation(List effectiveMonitoringFeature) { + List monitorItems = new ArrayList<>(); + Operation monitorOperation; + for (ProfileFeature profileFeature : effectiveMonitoringFeature) { + + if (profileFeature.getFeatureCode().equals(PluginConstants + .OperationCodes.CAMERA)) { + String cameraStatus = PluginConstants + .OperationCodes.CAMERA_STATUS; + + monitorOperation = new Operation(); + monitorOperation.setCode(cameraStatus); + Item item = appendGetInfo(monitorOperation); + monitorItems.add(item); + } + if (profileFeature.getFeatureCode().equals(PluginConstants + .OperationCodes.ENCRYPT_STORAGE)) { + String encryptStorageStatus = PluginConstants + .OperationCodes.ENCRYPT_STORAGE_STATUS; + + monitorOperation = new Operation(); + monitorOperation.setCode(encryptStorageStatus); + Item item = appendGetInfo(monitorOperation); + monitorItems.add(item); + } + if (profileFeature.getFeatureCode().equals(PluginConstants + .OperationCodes.PASSCODE_POLICY)) { + String passcodeStatus = PluginConstants + .OperationCodes.DEVICE_PASSWORD_STATUS; + + monitorOperation = new Operation(); + monitorOperation.setCode(passcodeStatus); + Item item = appendGetInfo(monitorOperation); + monitorItems.add(item); + } + } + return monitorItems; + } + + public List buildDeleteInfo(Operation operation) { + List deleteItems = new ArrayList<>(); + Item deleteItem = new Item(); + Target target = new Target(); + String operationCode = operation.getCode(); + if (operation.getCode().equals(PluginConstants.OperationCodes.PASSCODE_POLICY)) { + operation.setCode(PluginConstants.OperationCodes.DEVICE_PASSCODE_DELETE); + for (Command command : Command.values()) { + + if (operationCode != null && operationCode.equals(command.name())) { + target.setLocURI(command.getCode()); + deleteItem.setTarget(target); + } + } + } + return deleteItems; + } + + public AddTag generatePasscodePolicyData(Configure configure, int policyData) { + String attempt = String.valueOf(policyData); + AddTag add = new AddTag(); + List itemList = new ArrayList<>(); + Item item = new Item(); + Target target = new Target(); + target.setLocURI(configure.getCode()); + MetaTag meta = new MetaTag(); + meta.setFormat(Constants.META_FORMAT_INT); + item.setTarget(target); + item.setMeta(meta); + item.setData(attempt); + itemList.add(item); + add.setCommandId(90); + add.setItems(itemList); + return add; + } + + public AddTag generatePasscodeBooleanData(Operation operation, Configure configure) { + Target target = new Target(); + MetaTag meta = new MetaTag(); + AddTag add = new AddTag(); + + PasscodePolicy passcodePolicy = gson.fromJson((String) operation.getPayLoad(), PasscodePolicy.class); + if (operation.getCode() != null && (PluginConstants.OperationCodes.DEVICE_PASSWORD_ENABLE. + equals(configure.name()))) { + if (passcodePolicy.isEnablePassword()) { + target.setLocURI(configure.getCode()); + meta.setFormat(Constants.META_FORMAT_INT); + List itemList = new ArrayList<>(); + Item item = new Item(); + item.setTarget(target); + item.setMeta(meta); + item.setData("0"); + itemList.add(item); + + add.setCommandId(operation.getId()); + add.setItems(itemList); + + } else { + target.setLocURI(configure.getCode()); + meta.setFormat(Constants.META_FORMAT_INT); + List itemList = new ArrayList<>(); + Item item = new Item(); + item.setTarget(target); + item.setMeta(meta); + item.setData("1"); + itemList.add(item); + add.setCommandId(operation.getId()); + add.setItems(itemList); + + } + } + if (PluginConstants.OperationCodes.ALPHANUMERIC_PASSWORD. + equals(configure.name())) { + if (passcodePolicy.isRequireAlphanumeric()) { + Item item = new Item(); + target.setLocURI(configure.getCode()); + meta.setFormat(Constants.META_FORMAT_INT); + List itemList = new ArrayList<>(); + item.setTarget(target); + item.setMeta(meta); + item.setData("1"); + itemList.add(item); + add.setCommandId(operation.getId()); + add.setItems(itemList); + } else { + target.setLocURI(configure.getCode()); + meta.setFormat(Constants.META_FORMAT_INT); + List itemList = new ArrayList<>(); + Item item = new Item(); + item.setTarget(target); + item.setMeta(meta); + item.setData("0"); + itemList.add(item); + add.setCommandId(operation.getId()); + add.setItems(itemList); + } + } + if (PluginConstants.OperationCodes.SIMPLE_PASSWORD. + equals(configure.name())) { + if (passcodePolicy.isAllowSimple()) { + Item item = new Item(); + target.setLocURI(configure.getCode()); + meta.setFormat(Constants.META_FORMAT_INT); + List itemList = new ArrayList<>(); + item.setTarget(target); + item.setMeta(meta); + item.setData("1"); + itemList.add(item); + add.setCommandId(operation.getId()); + add.setItems(itemList); + + } else { + Item item = new Item(); + target.setLocURI(configure.getCode()); + meta.setFormat(Constants.META_FORMAT_INT); + List itemList = new ArrayList<>(); + item.setTarget(target); + item.setMeta(meta); + item.setData("0"); + itemList.add(item); + add.setCommandId(operation.getId()); + add.setItems(itemList); + } + } + return add; + } + +} + + + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationUtils.java new file mode 100644 index 000000000..4f223df0c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationUtils.java @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.FeatureManagementException; +import org.wso2.carbon.device.mgt.common.notification.mgt.Notification; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.mdm.mobileservices.windows.operations.*; +import org.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans.Profile; +import org.wso2.carbon.policy.mgt.common.ProfileFeature; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceFeature; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; + +import java.util.ArrayList; +import java.util.List; + +import static org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils.convertToDeviceIdentifierObject; + +/** + * Class contains Operation related utilities. + */ +public class OperationUtils { + private static Log log = LogFactory.getLog(OperationUtils.class); + List pendingDataOperations; + + + /** + * Update the operations using device status payload. + * + * @param status Client side status for the specific operations + * @param syncmlDocument syncml payload for operation status which parse through the syncml engine + * @param deviceIdentifier specific device identifier for each device + * @throws OperationManagementException + * @throws DeviceManagementException + */ + public void updateDeviceOperations(Status status, SyncmlDocument syncmlDocument, + DeviceIdentifier deviceIdentifier) + throws OperationManagementException, DeviceManagementException, NotificationManagementException, + WindowsOperationException { + + pendingDataOperations = WindowsAPIUtils.getDeviceManagementService() + .getOperationsByDeviceAndStatus(deviceIdentifier, Operation.Status.PENDING); + if (status.getData().equals(Constants.SyncMLResponseCodes.ACCEPTED) || status.getData().equals + (Constants.SyncMLResponseCodes.ACCEPTED_FOR_PROCESSING)) { + for (Operation operation : pendingDataOperations) { + if (operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.COMPLETED); + } + } + updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), pendingDataOperations); + } else if (status.getData().equals(Constants.SyncMLResponseCodes.PIN_NOTFOUND)) { + for (Operation operation : pendingDataOperations) { + if (operation.getId() == status.getCommandReference() && operation. + getCode().equals(String.valueOf(OperationCode.Command.DEVICE_LOCK))) { + operation.setStatus(Operation.Status.ERROR); + updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), pendingDataOperations); + try { + NotificationManagementService nmService = WindowsAPIUtils.getNotificationManagementService(); + Notification lockResetNotification = new Notification(); + lockResetNotification.setOperationId(status.getCommandReference()); + lockResetNotification.setStatus(String.valueOf(Notification.Status.NEW)); + lockResetNotification.setDeviceIdentifier(deviceIdentifier); + lockResetNotification.setDescription( + Constants.SyncMLResponseCodes.LOCKRESET_NOTIFICATION); + nmService.addNotification(lockResetNotification); + } catch (NotificationManagementException e) { + throw new WindowsOperationException("Failure occurred in getting notification service", e); + } + } + } + } + } + + /** + * Update operation statuses + * + * @param deviceId specific device Id + * @param operations operation list to be update + * @throws OperationManagementException + */ + public void updateOperations(String deviceId, + List operations) + throws OperationManagementException { + + for (Operation operation : operations) { + WindowsAPIUtils.updateOperation(deviceId, operation); + if (log.isDebugEnabled()) { + log.debug("Updating operation '" + operation.toString() + "'"); + } + } + } + + /** + * Update Status of the lock operation. + * + * @param status Status of the operation. + * @param syncmlDocument parsed syncml payload. + * @param deviceIdentifier Device Id. + * @throws OperationManagementException + * @throws DeviceManagementException + * @throws NotificationManagementException + */ + public void lockOperationUpdate(Status status, SyncmlDocument syncmlDocument, DeviceIdentifier deviceIdentifier) + throws OperationManagementException, DeviceManagementException, NotificationManagementException { + + pendingDataOperations = WindowsAPIUtils.getDeviceManagementService() + .getOperationsByDeviceAndStatus(deviceIdentifier, Operation.Status.PENDING); + if (status.getData().equals(Constants.SyncMLResponseCodes.ACCEPTED)) { + for (Operation operation : pendingDataOperations) { + if (operation.getCode().equals(OperationCode.Command.DEVICE_LOCK.getCode()) + && operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.COMPLETED); + new OperationUtils().updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), + pendingDataOperations); + } + } + } + if (status.getData().equals(Constants.SyncMLResponseCodes.PIN_NOTFOUND)) { + for (Operation operation : pendingDataOperations) { + + if (operation.getCode().equals(OperationCode.Command.DEVICE_LOCK.getCode()) && + operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.ERROR); + new OperationUtils().updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), + pendingDataOperations); + try { + NotificationManagementService nmService = WindowsAPIUtils.getNotificationManagementService(); + Notification lockResetNotification = new Notification(); + lockResetNotification.setOperationId(status.getCommandReference()); + lockResetNotification.setStatus(String.valueOf(Notification.Status.NEW)); + lockResetNotification.setDeviceIdentifier(deviceIdentifier); + lockResetNotification.setDescription(Constants.SyncMLResponseCodes.LOCKRESET_NOTIFICATION); + + nmService.addNotification(lockResetNotification); + } catch (NotificationManagementException e) { + String msg = "Failure occurred in getting notification service"; + log.error(msg, e); + throw new NotificationManagementException(msg, e); + } + } + } + } + } + + /*** + * Update status of the ring operation. + * + * @param status Ring status of the device. + * @param syncmlDocument Parsed syncml payload from the syncml engine. + * @param deviceIdentifier specific device id to be update. + * @throws OperationManagementException + * @throws DeviceManagementException + */ + public void ring(Status status, SyncmlDocument syncmlDocument, + DeviceIdentifier deviceIdentifier) + throws OperationManagementException, DeviceManagementException { + + if (status.getData().equals(Constants.SyncMLResponseCodes.ACCEPTED)) { + pendingDataOperations = WindowsAPIUtils.getDeviceManagementService() + .getOperationsByDeviceAndStatus(deviceIdentifier, Operation.Status.PENDING); + for (Operation operation : pendingDataOperations) { + if (operation.getCode().equals(OperationCode.Command.DEVICE_RING) && + (operation.getId() == status.getCommandReference())) { + operation.setStatus(Operation.Status.COMPLETED); + new OperationUtils().updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), + pendingDataOperations); + } + } + } + } + + /*** + * Update the status of the DataWipe operation. + * + * @param status Status of the datawipe. + * @param syncmlDocument Parsed syncml payload from the syncml engine. + * @param deviceIdentifier specific device id to be wiped. + * @throws OperationManagementException + * @throws DeviceManagementException + */ + public void dataWipe(Status status, SyncmlDocument syncmlDocument, + DeviceIdentifier deviceIdentifier) + throws OperationManagementException, DeviceManagementException { + + if (status.getData().equals(Constants.SyncMLResponseCodes.ACCEPTED)) { + pendingDataOperations = WindowsAPIUtils.getDeviceManagementService() + .getOperationsByDeviceAndStatus(deviceIdentifier, Operation.Status.PENDING); + for (Operation operation : pendingDataOperations) { + + if (operation.getCode().equals(OperationCode.Command.WIPE_DATA) && + (operation.getId() == status.getCommandReference())) { + operation.setStatus(Operation.Status.COMPLETED); + updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), + pendingDataOperations); + } + } + } + } + + /** + * Get pending operations. + * + * @param syncmlDocument SyncmlDocument object which creates from the syncml engine using syncml payload + * @return Return list of pending operations. + * @throws OperationManagementException + * @throws DeviceManagementException + * @throws FeatureManagementException + * @throws PolicyComplianceException + * @throws NotificationManagementException + */ + public List getPendingOperations(SyncmlDocument syncmlDocument) + throws OperationManagementException, DeviceManagementException, FeatureManagementException, + PolicyComplianceException, NotificationManagementException, WindowsDeviceEnrolmentException, + WindowsOperationException { + + List pendingOperations; + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject( + syncmlDocument.getHeader().getSource().getLocURI()); + UpdateUriOperations(syncmlDocument); + generateComplianceFeatureStatus(syncmlDocument); + + pendingOperations = WindowsAPIUtils.getDeviceManagementService().getPendingOperations(deviceIdentifier); + return pendingOperations; + } + + /** + * Set compliance of the feature according to the device status for the specific feature. + * + * @param activeFeature + * @param deviceFeature + * @return Returns setting up compliance feature. + */ + public ComplianceFeature setComplianceFeatures(ProfileFeature activeFeature, Profile deviceFeature) { + ComplianceFeature complianceFeature = new ComplianceFeature(); + complianceFeature.setFeature(activeFeature); + complianceFeature.setFeatureCode(activeFeature.getFeatureCode()); + complianceFeature.setCompliance(deviceFeature.isCompliance()); + return complianceFeature; + } + + /** + * Update the completed/Error status of the operation which have the URI of the operation code in the syncml payload. + * + * @param syncmlDocument SyncmlDocument object generated from the the syncml engine. + * @throws DeviceManagementException + * @throws NotificationManagementException + * @throws OperationManagementException + */ + public void UpdateUriOperations(SyncmlDocument syncmlDocument) throws DeviceManagementException, + NotificationManagementException, OperationManagementException, WindowsOperationException { + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject( + syncmlDocument.getHeader().getSource().getLocURI()); + List statuses = syncmlDocument.getBody().getStatus(); + OperationUtils operationUtils = new OperationUtils(); + + for (Status status : statuses) { + + if (status.getCommand().equals(Constants.EXECUTE)) { + if (status.getTargetReference() == null) { + operationUtils.updateDeviceOperations(status, syncmlDocument, deviceIdentifier); + } else { + if (status.getTargetReference().equals(OperationCode.Command.DEVICE_LOCK)) { + operationUtils.lockOperationUpdate(status, syncmlDocument, deviceIdentifier); + } + if (status.getTargetReference().equals(OperationCode.Command.DEVICE_RING)) { + operationUtils.ring(status, syncmlDocument, deviceIdentifier); + } + if (status.getTargetReference().equals(OperationCode.Command.WIPE_DATA)) { + operationUtils.dataWipe(status, syncmlDocument, deviceIdentifier); + } + } + } + if (status.getCommand().equals(Constants.SEQUENCE)) { + if (status.getData().equals(Constants.SyncMLResponseCodes.ACCEPTED)) { + + pendingDataOperations = WindowsAPIUtils.getDeviceManagementService() + .getOperationsByDeviceAndStatus(deviceIdentifier, Operation.Status.PENDING); + for (Operation operation : pendingDataOperations) { + if (operation.getCode().equals(PluginConstants.OperationCodes.POLICY_BUNDLE) && + operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.COMPLETED); + } + if (operation.getCode().equals(PluginConstants.OperationCodes.MONITOR) && + operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.COMPLETED); + } + } + operationUtils.updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), + pendingDataOperations); + } else { + pendingDataOperations = WindowsAPIUtils.getDeviceManagementService() + .getOperationsByDeviceAndStatus(deviceIdentifier, Operation.Status.PENDING); + for (Operation operation : pendingDataOperations) { + + if (operation.getCode().equals(PluginConstants.OperationCodes.POLICY_BUNDLE) && + operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.ERROR); + } + if (operation.getCode().equals(PluginConstants.OperationCodes.MONITOR) && + operation.getId() == status.getCommandReference()) { + operation.setStatus(Operation.Status.ERROR); + } + } + operationUtils.updateOperations(syncmlDocument.getHeader().getSource().getLocURI(), + pendingDataOperations); + } + } + } + } + + /** + * Generate status of the features that have been activated on the device. + * + * @param syncmlDocument syncmlDocument object pasrsed from the syncml engine. + * @return device statuses for the activated features + * @throws NotificationManagementException + */ + public List generateDeviceOperationStatusObject(SyncmlDocument syncmlDocument) throws + NotificationManagementException, WindowsOperationException { + + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject( + syncmlDocument.getHeader().getSource().getLocURI()); + String lockUri = null; + Results result = syncmlDocument.getBody().getResults(); + + List profiles = new ArrayList<>(); + if (result != null) { + List results = result.getItem(); + for (OperationCode.Info info : OperationCode.Info.values()) { + if (PluginConstants.OperationCodes.PIN_CODE.equals(info + .name())) { + lockUri = info.getCode(); + } + } + for (Item item : results) { + for (OperationCode.Info info : OperationCode.Info.values()) { + if (item.getSource().getLocURI().equals(info.getCode()) && info.name().equals( + PluginConstants.OperationCodes.CAMERA_STATUS)) { + Profile cameraProfile = new Profile(); + cameraProfile.setFeatureCode(PluginConstants.OperationCodes.CAMERA); + cameraProfile.setData(item.getData()); + if (item.getData().equals(PluginConstants.SyncML.SYNCML_DATA_ONE)) { + cameraProfile.setEnable(true); + } else { + cameraProfile.setEnable(false); + } + profiles.add(cameraProfile); + } + if (item.getSource().getLocURI().equals(info.getCode()) && info.name().equals( + PluginConstants.OperationCodes.ENCRYPT_STORAGE_STATUS)) { + Profile encryptStorage = new Profile(); + encryptStorage.setFeatureCode(PluginConstants.OperationCodes.ENCRYPT_STORAGE); + encryptStorage.setData(item.getData()); + if (item.getData().equals(PluginConstants.SyncML.SYNCML_DATA_ONE)) { + encryptStorage.setEnable(true); + } else { + encryptStorage.setEnable(false); + } + profiles.add(encryptStorage); + } + if (item.getSource().getLocURI().equals(info.getCode()) && info.name().equals( + PluginConstants.OperationCodes.DEVICE_PASSWORD_STATUS)) { + Profile encryptStorage = new Profile(); + encryptStorage.setFeatureCode(PluginConstants.OperationCodes.PASSCODE_POLICY); + encryptStorage.setData(item.getData()); + if (item.getData().equals(PluginConstants.SyncML.SYNCML_DATA_ZERO)) { + encryptStorage.setEnable(true); + } else { + encryptStorage.setEnable(false); + } + profiles.add(encryptStorage); + } + if (!item.getData().isEmpty() && item.getSource().getLocURI().equals(lockUri)) { + String pinValue = item.getData(); + NotificationManagementService nmService = WindowsAPIUtils.getNotificationManagementService(); + Notification notification = new Notification(); + notification.setDescription("Auto generated DevicePin : " + pinValue); + notification.setOperationId(result.getCommandReference()); + notification.setDeviceIdentifier(deviceIdentifier); + notification.setStatus(String.valueOf(Notification.Status.NEW)); + try { + nmService.addNotification(notification); + } catch (NotificationManagementException e) { + String msg = "Failure Occurred in getting notification service."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } + break; + } + } + } + } + return profiles; + } + + /** + * Generate Compliance Features + * + * @param syncmlDocument syncmlDocument object parsed from the syncml engine. + * @throws NotificationManagementException + * @throws FeatureManagementException + * @throws PolicyComplianceException + */ + public void generateComplianceFeatureStatus(SyncmlDocument syncmlDocument) throws NotificationManagementException, + FeatureManagementException, PolicyComplianceException, WindowsDeviceEnrolmentException, + WindowsOperationException { + List profiles = generateDeviceOperationStatusObject(syncmlDocument); + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject( + syncmlDocument.getHeader().getSource().getLocURI()); + boolean isCompliance = false; + if (profiles.size() != Constants.EMPTY) { + try { + List profileFeatures = WindowsAPIUtils.getPolicyManagerService().getEffectiveFeatures( + deviceIdentifier); + List complianceFeatures = new ArrayList<>(); + for (ProfileFeature activeFeature : profileFeatures) { + JSONObject policyContent = new JSONObject(activeFeature.getContent().toString()); + + for (Profile deviceFeature : profiles) { + if (deviceFeature.getFeatureCode().equals(activeFeature.getFeatureCode()) && + deviceFeature.getFeatureCode().equals(PluginConstants.OperationCodes.CAMERA)) { + if (policyContent.getBoolean(PluginConstants.PolicyConfigProperties. + POLICY_ENABLE) == (deviceFeature.isEnable())) { + isCompliance = true; + deviceFeature.setCompliance(isCompliance); + } else { + deviceFeature.setCompliance(isCompliance); + } + ComplianceFeature complianceFeature = setComplianceFeatures(activeFeature, deviceFeature); + complianceFeatures.add(complianceFeature); + } + if (deviceFeature.getFeatureCode().equals(activeFeature.getFeatureCode()) && + deviceFeature.getFeatureCode().equals(PluginConstants.OperationCodes. + ENCRYPT_STORAGE)) { + if (policyContent.getBoolean(PluginConstants.PolicyConfigProperties. + ENCRYPTED_ENABLE) == (deviceFeature.isEnable())) { + isCompliance = true; + deviceFeature.setCompliance(isCompliance); + } else { + deviceFeature.setCompliance(isCompliance); + } + ComplianceFeature complianceFeature = setComplianceFeatures(activeFeature, deviceFeature); + complianceFeatures.add(complianceFeature); + } + if (deviceFeature.getFeatureCode().equals(activeFeature.getFeatureCode()) && + deviceFeature.getFeatureCode().equals(PluginConstants.OperationCodes. + PASSCODE_POLICY)) { + if (policyContent.getBoolean(PluginConstants.PolicyConfigProperties. + ENABLE_PASSWORD) == (deviceFeature.isEnable())) { + isCompliance = true; + deviceFeature.setCompliance(isCompliance); + } else { + deviceFeature.setCompliance(isCompliance); + } + ComplianceFeature complianceFeature = setComplianceFeatures(activeFeature, deviceFeature); + complianceFeatures.add(complianceFeature); + } + } + } + WindowsAPIUtils.getPolicyManagerService().checkPolicyCompliance(deviceIdentifier, complianceFeatures); + } catch (org.wso2.carbon.policy.mgt.common.FeatureManagementException e) { + String msg = "Error occurred while getting effective policy."; + log.error(msg, e); + throw new FeatureManagementException(msg, e); + } catch (JSONException e) { + String msg = "Error occurred while parsing json object."; + log.error(msg); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (PolicyComplianceException e) { + String msg = "Error occurred while setting up policy compliance."; + log.error(msg, e); + throw new PolicyComplianceException(msg, e); + } + } + + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlCredentials.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlCredentials.java new file mode 100644 index 000000000..c807a23b1 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlCredentials.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +import org.apache.commons.codec.binary.Base64; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlMessageFormatException; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Class for generate security token for client and server. + */ +public class SyncmlCredentials { + + public String generateCredData(String nextNonce) throws SyncmlMessageFormatException { + MessageDigest digest; + String usrPwdNonceHash; + String nonce; + try { + nonce = new String(Base64.decodeBase64(nextNonce), Constants.UTF_8); + digest = MessageDigest.getInstance(Constants.MD5); + String usrPwd = Constants.PROVIDER_ID + ":" + Constants.SERVER_SECRET; + String usrPwdHash = Base64.encodeBase64String(digest.digest(usrPwd.getBytes(Constants.UTF_8))); + String usrPwdNonce = usrPwdHash + ":" + nonce; + usrPwdNonceHash = Base64.encodeBase64String(digest.digest(usrPwdNonce.getBytes(Constants.UTF_8))); + } catch (UnsupportedEncodingException e) { + throw new SyncmlMessageFormatException("Problem occurred in encoding credentials data.", e); + } catch (NoSuchAlgorithmException e) { + throw new SyncmlMessageFormatException("Problem occurred in generating password hash.", e); + } + return usrPwdNonceHash; + } + + public String generateRST(String username, String password) throws SyncmlMessageFormatException { + MessageDigest digest; + String usrPwdNonceHash; + String nonce; + try { + nonce = new String(Base64.decodeBase64(Constants.INITIAL_NONCE), Constants.UTF_8); + digest = MessageDigest.getInstance(Constants.MD5); + String usrPwd = username + ":" + password; + String usrPwdHash = Base64.encodeBase64String(digest.digest(usrPwd.getBytes(Constants.UTF_8))); + String usrPwdNonce = usrPwdHash + ":" + nonce; + usrPwdNonceHash = Base64.encodeBase64String(digest.digest(usrPwdNonce.getBytes(Constants.UTF_8))); + } catch (UnsupportedEncodingException e) { + throw new SyncmlMessageFormatException("Problem occurred in encoding credentials data.", e); + } catch (NoSuchAlgorithmException e) { + throw new SyncmlMessageFormatException("Problem occurred in generating password hash.", e); + } + return usrPwdNonceHash; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlGenerator.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlGenerator.java new file mode 100644 index 000000000..9591ca673 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlGenerator.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlOperationException; +import org.wso2.carbon.mdm.mobileservices.windows.operations.SyncmlBody; +import org.wso2.carbon.mdm.mobileservices.windows.operations.SyncmlDocument; +import org.wso2.carbon.mdm.mobileservices.windows.operations.SyncmlHeader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.*; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.StringWriter; + +/** + * Generates the response syncml xml file that should be sent to the phone. + */ +public class SyncmlGenerator { + + private static Log log = LogFactory.getLog(SyncmlGenerator.class); + + public String generatePayload(SyncmlDocument syncmlDocument) throws SyncmlOperationException { + Document doc = generateDocument(); + Element rootElement = createRootElement(doc); + SyncmlHeader header = syncmlDocument.getHeader(); + header.buildSyncmlHeaderElement(doc, rootElement); + SyncmlBody body = syncmlDocument.getBody(); + body.buildBodyElement(doc, rootElement); + return transformDocument(doc); + } + + private static Document generateDocument() throws SyncmlOperationException { + DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + try { + docBuilder = documentFactory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + String message = "Error while generating a new document of syncml"; + log.error(message, e); + throw new SyncmlOperationException(message, e); + } + return docBuilder.newDocument(); + } + + private static Element createRootElement(Document document) { + Element rootElement = document.createElementNS(Constants.XMLNS_SYNCML, + Constants.SYNCML_ROOT_ELEMENT_NAME); + document.appendChild(rootElement); + return rootElement; + } + + private String transformDocument(Document document) throws SyncmlOperationException { + DOMSource domSource = new DOMSource(document); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer; + try { + transformer = transformerFactory.newTransformer(); + } catch (TransformerConfigurationException e) { + String message = "Error while retrieving a new transformer"; + log.error(message, e); + throw new SyncmlOperationException(message, e); + } + transformer.setOutputProperty(OutputKeys.ENCODING, Constants.UTF_8); + transformer.setOutputProperty(OutputKeys.INDENT, Constants.YES); + + StringWriter stringWriter = new StringWriter(); + StreamResult streamResult = new StreamResult(stringWriter); + try { + transformer.transform(domSource, streamResult); + } catch (TransformerException e) { + String message = "Error while transforming document to a string"; + log.error(message, e); + throw new SyncmlOperationException(message, e); + } + return stringWriter.toString(); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlParser.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlParser.java new file mode 100644 index 000000000..836aa50be --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlParser.java @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.operations.util; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlMessageFormatException; +import org.wso2.carbon.mdm.mobileservices.windows.operations.*; + +import java.util.ArrayList; +import java.util.IllegalFormatCodePointException; +import java.util.List; + +/** + * Parses the receiving SyncML payload and generates the SyncML document object from it. + */ +public class SyncmlParser { + + private static String commandId; + private static String messageReference; + private static String commandReference; + private static final String SYNC_HEADER = "SyncHdr"; + private static final String SYNC_BODY = "SyncBody"; + + private enum SyncMLHeaderParameter { + MSG_ID("MsgID"), + SESSION_ID("SessionID"), + TARGET("Target"), + SOURCE("Source"), + CRED("Cred"); + private final String parameterName; + + SyncMLHeaderParameter(final String parameterName) { + this.parameterName = parameterName; + } + + public String getValue() { + return this.parameterName; + } + } + + private enum SycMLCommandType { + ALERT("Alert"), + REPLACE("Replace"), + STATUS("Status"), + RESULTS("Results"); + private final String commandName; + + SycMLCommandType(final String commandName) { + this.commandName = commandName; + } + + public String getValue() { + return this.commandName; + } + } + + + /** + * Parses the raw SyncML payload and generates a SyncmlDocument object using the parsed XML contents. + * + * @param syncmlPayload - Received SyncML XML payload + * @return - SyncmlDocument object generated from the received payload + */ + public static SyncmlDocument parseSyncmlPayload(Document syncmlPayload) throws SyncmlMessageFormatException { + SyncmlDocument syncmlDocument = new SyncmlDocument(); + if (syncmlPayload.getElementsByTagName(SYNC_HEADER) == null) { + throw new SyncmlMessageFormatException(); + } + NodeList syncHeaderList = syncmlPayload.getElementsByTagName(SYNC_HEADER); + Node syncHeader = syncHeaderList.item(0); + SyncmlHeader header = generateSyncmlHeader(syncHeader); + + NodeList syncBodyList = syncmlPayload.getElementsByTagName(SYNC_BODY); + Node syncBody = syncBodyList.item(0); + SyncmlBody body = generateSyncmlBody(syncBody); + + syncmlDocument.setHeader(header); + syncmlDocument.setBody(body); + return syncmlDocument; + } + + /** + * Generates SyncmlHeader object by extracting properties of passed XML node. + * + * @param syncHeader - XML node which represents SyncML header + * @return - SyncmlHeader object + */ + private static SyncmlHeader generateSyncmlHeader(Node syncHeader) { + + String sessionID = null; + String messageID = null; + Target target = null; + Source source = null; + Credential credential = null; + SyncmlHeader header = new SyncmlHeader(); + + NodeList headerElements = syncHeader.getChildNodes(); + for (int i = 0; i < headerElements.getLength(); i++) { + Node node = headerElements.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + String nodeName = node.getNodeName(); + + if (SyncMLHeaderParameter.MSG_ID.getValue().equals(nodeName)) { + if (node.getTextContent().trim() == null) { + throw new IllegalFormatCodePointException(2); + } else { + messageID = node.getTextContent().trim(); + } + } else if (SyncMLHeaderParameter.SESSION_ID.getValue().equals(nodeName)) { + if (node.getTextContent().trim() == null) { + throw new IllegalFormatCodePointException(2); + } else { + sessionID = node.getTextContent().trim(); + } + } else if (SyncMLHeaderParameter.TARGET.getValue().equals(nodeName)) { + if (node.getTextContent().trim() == null) { + throw new IllegalFormatCodePointException(2); + } else { + target = generateTarget(node); + } + } else if (SyncMLHeaderParameter.SOURCE.getValue().equals(nodeName)) { + if (node.getTextContent().trim() == null) { + throw new IllegalFormatCodePointException(2); + } else { + source = generateSource(node); + } + } else if (SyncMLHeaderParameter.CRED.getValue().equals(nodeName)) { + if (node.getTextContent().trim() == null) { + throw new IllegalFormatCodePointException(2); + } else { + credential = generateCredential(node); + } + } + } + } + header.setMsgID(Integer.valueOf(messageID)); + // Syncml message contains a sessionID which is Hexadecimal value.Hexadecimal sessionID parse as a integer value. + header.setSessionId(Integer.valueOf(sessionID, 16)); + header.setTarget(target); + header.setSource(source); + header.setCredential(credential); + return header; + } + + /** + * Generates SyncmlBody object by extracting properties of passed XML node. + * + * @param syncBody - XML node which represents SyncML body + * @return - SyncmlBody object + */ + private static SyncmlBody generateSyncmlBody(Node syncBody) { + + Alert alert = null; + Replace replace = null; + Results results = null; + List status = new ArrayList<>(); + NodeList bodyElements = syncBody.getChildNodes(); + + for (int i = 0; i < bodyElements.getLength(); i++) { + Node node = bodyElements.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + String nodeName = node.getNodeName(); + + if (SycMLCommandType.ALERT.getValue().equals(nodeName)) { + alert = generateAlert(node); + } else if (SycMLCommandType.REPLACE.getValue().equals(nodeName)) { + replace = generateReplace(node); + } else if (SycMLCommandType.STATUS.getValue().equals(nodeName)) { + status.add(generateStatus(node)); + } else if (SycMLCommandType.RESULTS.getValue().equals(nodeName)) { + results = generateResults(node); + } + } + } + SyncmlBody body = new SyncmlBody(); + body.setAlert(alert); + body.setReplace(replace); + body.setStatus(status); + body.setResults(results); + return body; + } + + /** + * Generates Source object by extracting properties of passed XML node. + * + * @param node - XML node which represents Source + * @return - Source object + */ + private static Source generateSource(Node node) { + + Source source = new Source(); + Node sourceURIItem = node.getChildNodes().item(0); + Node sourceNameItem = node.getChildNodes().item(1); + String sourceURI = null; + String sourceName = null; + + if (sourceURIItem != null) { + sourceURI = sourceURIItem.getTextContent().trim(); + } + if (sourceNameItem != null) { + sourceName = sourceNameItem.getTextContent().trim(); + } + source.setLocURI(sourceURI); + source.setLocName(sourceName); + return source; + } + + /** + * Generates Target object by extracting properties of passed XML node. + * + * @param node - XML node which represents Target + * @return - Target object + */ + private static Target generateTarget(Node node) { + + Target target = new Target(); + Node targetURIItem = node.getChildNodes().item(0); + Node targetNameItem = node.getChildNodes().item(1); + String targetURI = null; + String targetName = null; + + if (targetURIItem != null) { + targetURI = targetURIItem.getTextContent().trim(); + } + if (targetNameItem != null) { + targetName = targetNameItem.getTextContent().trim(); + } + target.setLocURI(targetURI); + target.setLocName(targetName); + return target; + } + + /** + * Generates Results object by extracting properties of passed XML node. + * + * @param node - XML node which represents Results + * @return - Results object + */ + private static Results generateResults(Node node) { + + Results results = new Results(); + List item = new ArrayList<>(); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + + NodeList nodelist = node.getChildNodes(); + + for (int i = 0; i < nodelist.getLength(); i++) { + String nodeName = nodelist.item(i).getNodeName(); + + switch (nodeName) { + case Constants.COMMAND_ID: + commandId = node.getChildNodes().item(i).getTextContent().trim(); + break; + case Constants.MESSAGE_REFERENCE: + messageReference = node.getChildNodes().item(i).getTextContent().trim(); + break; + case Constants.COMMAND_REFERENCE: + commandReference = node.getChildNodes().item(i).getTextContent().trim(); + break; + case Constants.ITEM: + item.add(generateItem(node.getChildNodes().item(i))); + break; + } + } + results.setCommandId(Integer.valueOf(commandId)); + results.setMessageReference(Integer.valueOf(messageReference)); + results.setCommandReference(Integer.valueOf(commandReference)); + results.setItem(item); + } + return results; + } + + /** + * Generates Status object by extracting properties of passed XML node. + * + * @param node - XML node which represents Status + * @return - Status object + */ + private static Status generateStatus(Node node) { + + Status status = new Status(); + for (int x = 0; x < node.getChildNodes().getLength(); x++) { + String nodeName = node.getChildNodes().item(x).getNodeName(); + switch (nodeName) { + case PluginConstants.SyncML.SYNCML_CMD_ID: + String commandId = node.getChildNodes().item(x).getTextContent().trim(); + status.setCommandId(Integer.valueOf(commandId)); + break; + case PluginConstants.SyncML.SYNCML_MESSAGE_REF: + String messageReference = node.getChildNodes().item(x).getTextContent().trim(); + status.setMessageReference(Integer.valueOf(messageReference)); + break; + case PluginConstants.SyncML.SYNCML_CMD_REF: + String commandReference = node.getChildNodes().item(x).getTextContent().trim(); + status.setCommandReference(Integer.valueOf(commandReference)); + break; + case PluginConstants.SyncML.SYNCML_CMD: + String command = node.getChildNodes().item(x).getTextContent().trim(); + status.setCommand(command); + break; + case PluginConstants.SyncML.SYNCML_CHAL: + NodeList chalNodes = node.getChildNodes().item(x).getChildNodes(); + MetaTag meta = new MetaTag(); + ChallengeTag chal = new ChallengeTag(); + String format = chalNodes.item(0).getFirstChild().getTextContent(); + meta.setFormat(format); + String type = chalNodes.item(0).getFirstChild().getNextSibling().getTextContent(); + meta.setType(type); + String nonce = chalNodes.item(0).getFirstChild().getNextSibling().getNextSibling().getTextContent(); + meta.setNextNonce(nonce); + chal.setMeta(meta); + status.setChallenge(chal); + break; + case PluginConstants.SyncML.SYNCML_DATA: + String data = node.getChildNodes().item(x).getTextContent().trim(); + status.setData(data); + break; + case PluginConstants.SyncML.SYNCML_TARGET_REF: + String targetReference = node.getChildNodes().item(x).getTextContent().trim(); + status.setTargetReference(targetReference); + break; + } + } + return status; + } + + /** + * Generates Replace object by extracting properties of passed XML node. + * + * @param node - XML node which represents Replace + * @return - Replace object + */ + private static Replace generateReplace(Node node) { + + Replace replace = new Replace(); + String commandId = node.getChildNodes().item(0).getTextContent().trim(); + List items = new ArrayList<>(); + for (int i = 0; i < node.getChildNodes().getLength() - 1; i++) { + items.add(generateItem(node.getChildNodes().item(i + 1))); + } + replace.setCommandId(Integer.valueOf(commandId)); + replace.setItems(items); + return replace; + } + + /** + * Generates Alert object by extracting properties of passed XML node. + * + * @param node - XML node which represents Alert + * @return - Alert object + */ + private static Alert generateAlert(Node node) { + Alert alert = new Alert(); + String commandID = node.getChildNodes().item(0).getTextContent().trim(); + String data = node.getChildNodes().item(1).getTextContent().trim(); + alert.setCommandId(Integer.valueOf(commandID)); + alert.setData(data); + return alert; + } + + /** + * Generates Item object by extracting properties of passed XML node. + * + * @param node - XML node which represents Item + * @return - Item object + */ + private static Item generateItem(Node node) { + Item item = new Item(); + Source source = new Source(); + String data; + String nodeName; + String childNodeName; + String locUri; + for (int x = 0; x < node.getChildNodes().getLength(); x++) { + if (node.getChildNodes().item(x).getNodeName() != null) { + nodeName = node.getChildNodes().item(x).getNodeName(); + } else { + throw new IllegalFormatCodePointException(2); + } + if (nodeName == PluginConstants.SyncML.SYNCML_SOURCE) { + if (node.getChildNodes().item(x).getChildNodes().item(x).getNodeName() != null) { + childNodeName = node.getChildNodes().item(x).getChildNodes().item(x).getNodeName(); + } else { + throw new IllegalFormatCodePointException(2); + } + if (childNodeName == PluginConstants.SyncML.SYNCML_LOCATION_URI) { + if (node.getChildNodes().item(x).getChildNodes().item(x).getTextContent().trim() != null) { + locUri = node.getChildNodes().item(x).getChildNodes().item(x).getTextContent().trim(); + } else { + throw new IllegalFormatCodePointException(2); + } + source.setLocURI(locUri); + item.setSource(source); + } + } else if (nodeName == PluginConstants.SyncML.SYNCML_DATA) { + if (node.getChildNodes().item(x).getTextContent().trim() != null) { + data = node.getChildNodes().item(x).getTextContent().trim(); + } else { + throw new IllegalFormatCodePointException(2); + } + item.setData(data); + } + } + return item; + } + + /** + * Generates Credential object by extracting properties of passed XML node. + * + * @param node - XML node which represents Credential + * @return - Credential object + */ + private static Credential generateCredential(Node node) { + Credential credential = new Credential(); + MetaTag meta = generateMeta(node.getChildNodes().item(0)); + String data = node.getChildNodes().item(1).getTextContent().trim(); + credential.setMeta(meta); + credential.setData(data); + return credential; + } + + /** + * Generates MetaTag object by extracting properties of passed XML node. + * + * @param node - XML node which represents MetaTag + * @return - MetaTag object + */ + private static MetaTag generateMeta(Node node) { + MetaTag meta = new MetaTag(); + String format = node.getChildNodes().item(0).getTextContent().trim(); + String type = node.getChildNodes().item(1).getTextContent().trim(); + meta.setFormat(format); + meta.setType(type); + return meta; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/Operations.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/Operations.java new file mode 100644 index 000000000..b96831f4b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/Operations.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations; + +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Interface for Admin operations persisting. This interface accepts operations added via UI. + */ +@Path("/operation") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) + +public interface Operations { + + @POST + @Path("/devicelock") + Response lock(@HeaderParam("Accept") String headerParam, List deviceids) throws WindowsDeviceEnrolmentException; + + @POST + @Path("/devicedisenroll") + Response disenroll(@HeaderParam("Accept") String headerParam, List deviceids) throws WindowsDeviceEnrolmentException; + + @POST + @Path("/devicewipe") + Response wipe(@HeaderParam("Accept") String headerParam, List deviceids) throws WindowsDeviceEnrolmentException; + + @POST + @Path("/devicering") + Response ring(@HeaderParam("Accept") String headerParam, List deviceids) throws WindowsDeviceEnrolmentException; + + @POST + @Path("/lockreset") + Response lockReset(@HeaderParam("Accept") String acceptHeader, List deviceids) + throws WindowsDeviceEnrolmentException; +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Device.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Device.java new file mode 100644 index 000000000..79a4af79c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Device.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans; + +/** + * Class for get device IDS. + */ +public class Device { + + private String id; + + public String getID() { + return id; + } + + public void setID(String id) { + this.id = id; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Disenrollment.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Disenrollment.java new file mode 100644 index 000000000..85054033b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Disenrollment.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans; + +import java.io.Serializable; + +/** + * Class for dis-enrollment operation + */ +public class Disenrollment implements Serializable { + + private boolean enabled; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + private boolean isEnable() { + return enabled; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationRequest.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationRequest.java new file mode 100644 index 000000000..0745aa53a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationRequest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans.BasicOperation; + +import java.util.List; + +/** + * Class for set basic operations. + */ +public class OperationRequest { + + private List deviceList; + private BasicOperation basicOperation; + + public BasicOperation getBasicOperation() { + return basicOperation; + } + + public void setBasicOperation(BasicOperation basicOperation) { + this.basicOperation = basicOperation; + } + + public List getDeviceList() { + return deviceList; + } + + public void setDeviceList(List deviceList) { + this.deviceList = deviceList; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationResponse.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationResponse.java new file mode 100644 index 000000000..d1ecce0e6 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationResponse.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans; + +/** + * This bean class is for credentials coming from wab page at federated authentication step. + */ +public class OperationResponse { + + private String errorCode; + private String statusCode; + + public OperationResponse() { + + } + + public String getErrorCode() { + return errorCode; + } + + public String getStatusCode() { + return statusCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public void setStatusCode(String statusCode) { + this.statusCode = statusCode; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/StorageEncryption.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/StorageEncryption.java new file mode 100644 index 000000000..9aaf4ce6f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/StorageEncryption.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans; + +import java.io.Serializable; + +/** + * This class represents the information of encrypt operation. + */ +public class StorageEncryption implements Serializable { + private boolean encrypted; + + public boolean isEncrypted() { + return encrypted; + } + + public void setEncrypted(boolean encrypted) { + this.encrypted = encrypted; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/DisenrollmentBeanWrapper.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/DisenrollmentBeanWrapper.java new file mode 100644 index 000000000..5f683e884 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/DisenrollmentBeanWrapper.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans.wrapper; + +import org.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans.Disenrollment; + +import java.util.List; + +/** + * Class is used to wrap dis-enrollment bean with the device + */ +public class DisenrollmentBeanWrapper { + + private Disenrollment operation; + + private List deviceId; + + public Disenrollment getOperation() { + return operation; + } + + public void setOperation(Disenrollment operation) { + this.operation = operation; + } + + public List getDeviceId() { + return deviceId; + } + + public void setDeviceId(List deviceId) { + this.deviceId = deviceId; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/EncryptBeanWrapper.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/EncryptBeanWrapper.java new file mode 100644 index 000000000..72181661a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/EncryptBeanWrapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans.wrapper; + +import org.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans.StorageEncryption; + +import java.util.List; + +/** + * This class is used to wrap the Encrypt bean with devices. + */ +public class EncryptBeanWrapper { + + private StorageEncryption operation; + private List deviceIDs; + + public StorageEncryption getOperation() { + return operation; + } + + public void setOperation(StorageEncryption operation) { + this.operation = operation; + } + + public List getDeviceIDs() { + return deviceIDs; + } + + public void setDeviceIDs(List deviceIDs) { + this.deviceIDs = deviceIDs; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/impl/OperationsImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/impl/OperationsImpl.java new file mode 100644 index 000000000..2a7cd96be --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/impl/OperationsImpl.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.impl; + +import com.ibm.wsdl.OperationImpl; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsOperationsException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.Message; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.Operations; + +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Implementation class of operations interface. Each method in this class receives the operations comes via UI + * and persists those in the correct format. + */ +public class OperationsImpl implements Operations { + + private static Log log = LogFactory.getLog(OperationImpl.class); + + /** + * REST endpoint for the Device Lock operation + * + * @param acceptHeader header value of the request POST message. + * @param deviceIDs list of device ids to be add device lockOperationUpdate operation. + * @return Response object for client. + * @throws WindowsDeviceEnrolmentException + */ + @POST + @Path("/lock") + public Response lock(@HeaderParam("Accept") String acceptHeader, List deviceIDs) + throws WindowsDeviceEnrolmentException { + if (log.isDebugEnabled()) { + log.debug("Invoking windows device lockOperationUpdate operation"); + } + MediaType responseMediaType = WindowsAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(PluginConstants.OperationCodes.DEVICE_LOCK); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(true); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } + } + + /** + * REST end point for device dis-enrollment. + * + * @param acceptHeader POST message header value. + * @param deviceIDs device ids to be dis-enrolled. + * @return Response object to the client. + * @throws WindowsDeviceEnrolmentException + */ + @POST + @Path("/disenroll") + public Response disenroll(@HeaderParam("Accept") String acceptHeader, List deviceIDs) + throws WindowsDeviceEnrolmentException { + + MediaType responseMediaType = WindowsAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + CommandOperation operation = new CommandOperation(); + operation.setCode(PluginConstants.OperationCodes.DISENROLL); + operation.setType(Operation.Type.COMMAND); + operation.setEnabled(true); + try { + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } + } + + /** + * REST Endpoint for the Device wipe. + * + * @param acceptHeader POST message header value. + * @param deviceids device ids to be wiped. + * @return Response object for the client. + * @throws WindowsDeviceEnrolmentException + */ + @POST + @Path("/wipe-data") + public Response wipe(@HeaderParam("Accept") String acceptHeader, List deviceids) + throws WindowsDeviceEnrolmentException { + + if (log.isDebugEnabled()) { + log.debug("Invoking windows wipe-data device operation"); + } + MediaType responseMediaType = WindowsAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + CommandOperation operation = new CommandOperation(); + operation.setCode(PluginConstants.OperationCodes.WIPE_DATA); + operation.setType(Operation.Type.COMMAND); + try { + return WindowsAPIUtils.getOperationResponse(deviceids, operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } + } + + /** + * REST end point for the device ring. + * + * @param acceptHeader post message header value. + * @param deviceIDs device ids to be ring. + * @return Response object for the client. + * @throws WindowsDeviceEnrolmentException + */ + @POST + @Path("/ring-device") + public Response ring(@HeaderParam("Accept") String acceptHeader, List deviceIDs) + throws WindowsDeviceEnrolmentException { + + if (log.isDebugEnabled()) { + log.debug("Invoking Windows ring-device device operation"); + } + MediaType responseMediaType = WindowsAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(PluginConstants.OperationCodes.DEVICE_RING); + operation.setType(Operation.Type.COMMAND); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } + } + + /** + * REST endpoint for the device lockOperationUpdate reset. + * Lock reset have to be done, when device user does not set PIN for the lockOperationUpdate screen. + * Admin set lockOperationUpdate operation for the specific device,If the device is in above scenario, + * admin will be notified.since + * admin have to set lockOperationUpdate reset operation to the device so that automatically generate PIN value for the + * lockOperationUpdate screen. + * + * @param acceptHeader POST message header value. + * @param deviceIDs Device ids to be lockOperationUpdate reset. + * @return Response object for the client. + * @throws WindowsDeviceEnrolmentException + */ + @POST + @Path("/lock-reset") + public Response lockReset(@HeaderParam("Accept") String acceptHeader, List deviceIDs) + throws WindowsDeviceEnrolmentException { + + if (log.isDebugEnabled()) { + log.debug("Invoking windows device lockReset storage operation"); + } + MediaType responseMediaType = WindowsAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + try { + CommandOperation operation = new CommandOperation(); + operation.setCode(PluginConstants.OperationCodes.LOCK_RESET); + operation.setType(Operation.Type.COMMAND); + return WindowsAPIUtils.getOperationResponse(deviceIDs, operation, message, responseMediaType); + } catch (OperationManagementException e) { + String errorMessage = "Issue in retrieving operation management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } catch (DeviceManagementException e) { + String errorMessage = "Issue in retrieving device management service instance"; + message.setResponseMessage(errorMessage); + message.setResponseCode(Response.Status.INTERNAL_SERVER_ERROR.toString()); + log.error(errorMessage, e); + throw new WindowsOperationsException(message, responseMediaType); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/util/OperationStore.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/util/OperationStore.java new file mode 100644 index 000000000..fe009c1f4 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/util/OperationStore.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, 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.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.util; + +import com.google.gson.Gson; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.operation.mgt.ConfigOperation; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.mdm.mobileservices.windows.common.SyncmlCommandType; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans.Device; +import org.wso2.carbon.mdm.mobileservices.windows.services.adminoperations.beans.OperationRequest; +import org.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans.Wifi; + +import java.util.ArrayList; +import java.util.List; + +public class OperationStore { + + private static Log log = LogFactory.getLog(OperationStore.class); + + public static boolean storeOperation(OperationRequest operationRequest, Operation.Type type, + String commandType) throws + WindowsDeviceEnrolmentException { + + List devices = operationRequest.getDeviceList(); + List deviceIdentifiers = new ArrayList(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + + Operation operation = transformBasicOperation(operationRequest, type, commandType); + + for (int i = 0; i < devices.size(); i++) { + try { + deviceIdentifier.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + deviceIdentifier.setId(devices.get(i).getID()); + deviceIdentifiers.add(deviceIdentifier); + getDeviceManagementServiceProvider().getDevice(deviceIdentifier); + + } catch (DeviceManagementException e) { + log.error("Cannot validate device ID: " + devices.get(i).getID()); + deviceIdentifiers.remove(i); + } + } + try { + getDeviceManagementServiceProvider().addOperation(operation, deviceIdentifiers); + } catch (OperationManagementException e) { + String msg = "Failure occurred while storing command operation."; + log.error(msg); + return false; + } + return true; + } + + private static DeviceManagementProviderService getDeviceManagementServiceProvider() { + DeviceManagementProviderService deviceManager; + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + deviceManager = + (DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + + if (deviceManager == null) { + String msg = "Device management service is not initialized."; + log.error(msg); + } + return deviceManager; + } + + private static Operation transformBasicOperation(OperationRequest operationRequest, Operation.Type type, + String commandType) throws WindowsDeviceEnrolmentException { + + Operation operation = new Operation(); + operation.setCode(commandType); + operation.setType(type); + Gson gson = new Gson(); + + if (commandType == SyncmlCommandType.WIFI.getValue()) { + + operation = new ConfigOperation(); + operation.setCode(commandType); + operation.setType(type); + + Wifi wifiObject = (Wifi) operationRequest.getBasicOperation(); + operation.setPayLoad(gson.toJson(wifiObject)); + } else { + // no operation..... + } + + return operation; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/BSTProvider.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/BSTProvider.java new file mode 100644 index 000000000..42660faea --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/BSTProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.authbst; + +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.services.authbst.beans.Credentials; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Interface for handling authentication request comes via MDM login page. + */ +@Path("/bst") +public interface BSTProvider { + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/authentication") + Response getBST(Credentials credentials) throws WindowsDeviceEnrolmentException; +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/beans/Credentials.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/beans/Credentials.java new file mode 100644 index 000000000..24be2d06c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/beans/Credentials.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.authbst.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * This bean class is for credentials coming from wab page at federated authentication step. + */ +@XmlRootElement(name = "credentials") +@XmlAccessorType(XmlAccessType.FIELD) +public class Credentials { + + @XmlElement(required = true, name = "username") + private String username; + @XmlElement(required = true, name = "email") + private String email; + @XmlElement(required = true, name = "password") + private String password; + @XmlElement(required = true, name = "ownership") + private String ownership; + @XmlElement(required = true, name = "token") + private String usertoken; + + public Credentials() { + + } + + public String getUsertoken() { + return usertoken; + } + + public void setUsertoken(String usertoken) { + this.usertoken = usertoken; + } + + public String getOwnership() { + return ownership; + } + + public void setOwnership(String ownership) { + this.ownership = ownership; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/impl/BSTProviderImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/impl/BSTProviderImpl.java new file mode 100644 index 000000000..9f8bd7b8a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/impl/BSTProviderImpl.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.authbst.impl; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.Token; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.AuthenticationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.DeviceUtil; +import org.wso2.carbon.mdm.mobileservices.windows.services.authbst.BSTProvider; +import org.wso2.carbon.mdm.mobileservices.windows.services.authbst.beans.Credentials; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import javax.ws.rs.core.Response; + +/** + * Implementation class of BSTProvider interface which authenticates the credentials comes via MDM login page. + */ +public class BSTProviderImpl implements BSTProvider { + + private static Log log = LogFactory.getLog(BSTProviderImpl.class); + private static final String DELIMITER = "@"; + + /** + * This method validates the device user, checking passed credentials and returns the corresponding + * binary security token which is used in XCEP and WSTEP stages for authentication. + * + * @param credentials - Credential object passes from the wab page + * @return - Response with binary security token + */ + @Override + public Response getBST(Credentials credentials) throws WindowsDeviceEnrolmentException { + + String domainUser = credentials.getUsername(); + String userToken = credentials.getUsertoken(); + String encodedToken; + try { + Token tokenBean = new Token(); + tokenBean.setChallengeToken(userToken); + Base64 base64 = new Base64(); + encodedToken = base64.encodeToString(userToken.getBytes()); + DeviceUtil.persistChallengeToken(encodedToken, null, domainUser); + JSONObject tokenContent = new JSONObject(); + tokenContent.put("UserToken", userToken); + return Response.ok().entity(tokenContent.toString()).build(); + } catch (DeviceManagementException e) { + String msg = "Failure occurred in generating challenge token."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (JSONException e) { + String msg = "Failure occurred in generating challenge token Json."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } + } + + /** + * This method authenticate the user checking the carbon default user store. + * + * @param username - Username in username token + * @param password - Password in username token + * @param tenantDomain - Tenant domain is extracted from the username + * @return - Returns boolean representing authentication result + * @throws AuthenticationException + */ + private boolean authenticate(String username, String password, String tenantDomain) throws + AuthenticationException { + + try { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + ctx.setTenantId(MultitenantConstants.SUPER_TENANT_ID); + RealmService realmService = (RealmService) ctx.getOSGiService(RealmService.class, null); + + if (realmService == null) { + String msg = "RealmService not initialized."; + log.error(msg); + throw new AuthenticationException(msg); + } + + int tenantId; + if (tenantDomain == null || tenantDomain.trim().isEmpty()) { + tenantId = MultitenantConstants.SUPER_TENANT_ID; + } else { + tenantId = realmService.getTenantManager().getTenantId(tenantDomain); + } + + if (tenantId == MultitenantConstants.INVALID_TENANT_ID) { + String msg = "Invalid tenant domain " + tenantDomain; + log.error(msg); + throw new AuthenticationException(msg); + } + UserRealm userRealm = realmService.getTenantUserRealm(tenantId); + + return userRealm.getUserStoreManager().authenticate(username, password); + } catch (UserStoreException e) { + String msg = "User store is not initialized."; + log.error(msg, e); + throw new AuthenticationException(msg, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/configurationmgtservice/ConfigurationMgtService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/configurationmgtservice/ConfigurationMgtService.java new file mode 100644 index 000000000..ae8e5f881 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/configurationmgtservice/ConfigurationMgtService.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.configurationmgtservice; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.license.mgt.License; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.Message; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Windows Platform Configuration REST-API implementation. + * All end points supports JSON, XMl with content negotiation. + */ +@WebService +@Produces({"application/json", "application/xml"}) +@Consumes({"application/json", "application/xml"}) +public class ConfigurationMgtService { + + private static Log log = LogFactory.getLog(ConfigurationMgtService.class); + + /** + * Save Tenant configurations. + * + * @param configuration Tenant Configurations to be saved. + * @return Message type object for the provide save status. + * @throws WindowsConfigurationException + */ + @POST + public Message ConfigureSettings(TenantConfiguration configuration) throws WindowsConfigurationException { + Message responseMsg = new Message(); + ConfigurationEntry licenseEntry = null; + String message; + + try { + configuration.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + if (!configuration.getConfiguration().isEmpty()) { + List configs = configuration.getConfiguration(); + for (ConfigurationEntry entry : configs) { + if (PluginConstants.TenantConfigProperties.LICENSE_KEY.equals(entry.getName())) { + License license = new License(); + license.setName(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + license.setLanguage(PluginConstants.TenantConfigProperties.LANGUAGE_US); + license.setVersion("1.0.0"); + license.setText(entry.getValue().toString()); + WindowsAPIUtils.getDeviceManagementService().addLicense(DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, license); + licenseEntry = entry; + } + } + + if (licenseEntry != null) { + configs.remove(licenseEntry); + } + configuration.setConfiguration(configs); + WindowsAPIUtils.getDeviceManagementService().saveConfiguration(configuration); + Response.status(Response.Status.CREATED); + responseMsg.setResponseMessage("Windows platform configuration saved successfully."); + responseMsg.setResponseCode(Response.Status.CREATED.toString()); + return responseMsg; + } + else { + Response.status(Response.Status.BAD_REQUEST); + responseMsg.setResponseMessage("Windows platform configuration can not be saved."); + responseMsg.setResponseCode(Response.Status.CREATED.toString()); + } + } catch (DeviceManagementException e) { + message = "Error Occurred in while configuring Windows Platform."; + log.error(message, e); + throw new WindowsConfigurationException(message, e); + } + return responseMsg; + } + + /** + * Retrieve Tenant configurations according to the device type. + * + * @return Tenant configuration object contains specific tenant configurations. + * @throws WindowsConfigurationException + */ + @GET + public TenantConfiguration getConfiguration() throws WindowsConfigurationException { + String msg; + TenantConfiguration tenantConfiguration = null; + try { + if (WindowsAPIUtils.getDeviceManagementService(). + getConfiguration(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS) != null) { + tenantConfiguration = WindowsAPIUtils.getDeviceManagementService(). + getConfiguration(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + List configs = tenantConfiguration.getConfiguration(); + ConfigurationEntry entry = new ConfigurationEntry(); + License license = WindowsAPIUtils.getDeviceManagementService().getLicense( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, PluginConstants. + TenantConfigProperties.LANGUAGE_US); + if(license != null) { + entry.setContentType(PluginConstants.TenantConfigProperties.CONTENT_TYPE_TEXT); + entry.setName(PluginConstants.TenantConfigProperties.LICENSE_KEY); + entry.setValue(license.getText()); + configs.add(entry); + tenantConfiguration.setConfiguration(configs); + } + } + } catch (DeviceManagementException e) { + msg = "Error occurred while retrieving the Windows tenant configuration"; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } + return tenantConfiguration; + } + + /** + * Update Tenant Configurations for the specific Device type. + * + * @param configuration Tenant configurations to be updated. + * @return Response message. + * @throws WindowsConfigurationException + */ + @PUT + public Message updateConfiguration(TenantConfiguration configuration) throws WindowsConfigurationException { + String message; + Message responseMsg = new Message(); + ConfigurationEntry licenseEntry = null; + try { + configuration.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + List configs = configuration.getConfiguration(); + for (ConfigurationEntry entry : configs) { + if (PluginConstants.TenantConfigProperties.LICENSE_KEY.equals(entry.getName())) { + License license = new License(); + license.setName(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + license.setLanguage(PluginConstants.TenantConfigProperties.LANGUAGE_US); + license.setVersion("1.0.0"); + license.setText(entry.getValue().toString()); + WindowsAPIUtils.getDeviceManagementService().addLicense(DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, license); + licenseEntry = entry; + } + } + + if (licenseEntry != null) { + configs.remove(licenseEntry); + } + configuration.setConfiguration(configs); + WindowsAPIUtils.getDeviceManagementService().saveConfiguration(configuration); + Response.status(Response.Status.CREATED); + responseMsg.setResponseMessage("Windows platform configuration succeeded."); + responseMsg.setResponseCode(Response.Status.CREATED.toString()); + } catch (DeviceManagementException e) { + message = "Error occurred while modifying configuration settings of Windows platform."; + log.error(message, e); + throw new WindowsConfigurationException(message, e); + } + return responseMsg; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/devicemgtservice/DeviceManagementService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/devicemgtservice/DeviceManagementService.java new file mode 100644 index 000000000..4e702f75e --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/devicemgtservice/DeviceManagementService.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.devicemgtservice; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.license.mgt.License; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.Message; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * Windows Device Management REST-API implementation. + * All end points supports JSON, XMl with content negotiation. + */ +@WebService +@Produces({"application/json", "application/xml"}) +@Consumes({"application/json", "application/xml"}) +public class DeviceManagementService { + + private static Log log = LogFactory.getLog(DeviceManagementService.class); + + /** + * Get all devices.Returns list of Windows devices registered in MDM. + * + * @return Device List + * @throws WindowsConfigurationException + */ + @GET + public List getAllDevices() + throws WindowsConfigurationException { + String msg; + List devices; + + try { + devices = WindowsAPIUtils.getDeviceManagementService(). + getAllDevices(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + } catch (DeviceManagementException e) { + msg = "Error occurred while fetching the device list."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } + return devices; + } + + /** + * Fetch Windows device details of a given device Id. + * + * @param id Device Id + * @return Device + * @throws WindowsConfigurationException + */ + @GET + @Path("{id}") + public org.wso2.carbon.device.mgt.common.Device getDevice(@PathParam("id") String id) + throws WindowsConfigurationException { + + String msg; + org.wso2.carbon.device.mgt.common.Device device; + + try { + DeviceIdentifier deviceIdentifier = WindowsAPIUtils.convertToDeviceIdentifierObject(id); + device = WindowsAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier); + if (device == null) { + Response.status(Response.Status.NOT_FOUND); + } + } catch (DeviceManagementException deviceMgtEx) { + msg = "Error occurred while fetching the device information."; + log.error(msg, deviceMgtEx); + throw new WindowsConfigurationException(msg, deviceMgtEx); + } + return device; + } + + /** + * Update Windows device details of given device id. + * + * @param id Device Id + * @param device Device Details + * @return Message + * @throws WindowsConfigurationException + */ + @PUT + @Path("{id}") + public Message updateDevice(@PathParam("id") String id, Device device) + throws WindowsConfigurationException { + String msg; + Message responseMessage = new Message(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(id); + deviceIdentifier + .setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + boolean result; + try { + device.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + result = WindowsAPIUtils.getDeviceManagementService() + .updateDeviceInfo(deviceIdentifier, device); + if (result) { + Response.status(Response.Status.ACCEPTED); + responseMessage.setResponseMessage("Device information has modified successfully."); + } else { + Response.status(Response.Status.NOT_MODIFIED); + responseMessage.setResponseMessage("Device not found for the update."); + } + } catch (DeviceManagementException e) { + msg = "Error occurred while modifying the device information."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } + return responseMessage; + } + + @GET + @Path("license") + @Produces("application/json") + public License getLicense() throws WindowsConfigurationException { + License license; + + try { + license = + WindowsAPIUtils.getDeviceManagementService().getLicense( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS, + DeviceManagementConstants.LanguageCodes.LANGUAGE_CODE_ENGLISH_US); + } catch (DeviceManagementException e) { + String msg = "Error occurred while retrieving the license configured for Windows device enrollment"; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } + return license; + } + +} + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/DiscoveryService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/DiscoveryService.java new file mode 100644 index 000000000..798403331 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/DiscoveryService.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.discovery; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans.DiscoveryRequest; +import org.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans.DiscoveryResponse; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.core.Response; +import javax.xml.ws.BindingType; +import javax.xml.ws.RequestWrapper; +import javax.xml.ws.ResponseWrapper; +import javax.xml.ws.soap.SOAPBinding; + +/** + * Interface for Discovery service related operations. + */ +@WebService(targetNamespace = PluginConstants.DISCOVERY_SERVICE_TARGET_NAMESPACE, + name = "IDiscoveryService") +@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) +public interface DiscoveryService { + + @POST + @RequestWrapper(localName = "Discover", targetNamespace = PluginConstants.DISCOVERY_SERVICE_TARGET_NAMESPACE) + @WebMethod(operationName = "Discover") + @ResponseWrapper(localName = "DiscoverResponse", targetNamespace = PluginConstants.DISCOVERY_SERVICE_TARGET_NAMESPACE) + void discover( + @WebParam(name = "request", targetNamespace = PluginConstants.DISCOVERY_SERVICE_TARGET_NAMESPACE) + DiscoveryRequest request, + @WebParam(mode = WebParam.Mode.OUT, name = "DiscoverResult", + targetNamespace = PluginConstants.DISCOVERY_SERVICE_TARGET_NAMESPACE) + javax.xml.ws.Holder response + ); + + @GET + @WebMethod + @WebResult() + Response discoverGet(); + +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryRequest.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryRequest.java new file mode 100644 index 000000000..9acd44f0f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans; + +import javax.xml.bind.annotation.*; +import java.io.Serializable; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "DiscoveryRequest") +@SuppressWarnings("unused") +public class DiscoveryRequest implements Serializable { + + @XmlElement(name = "EmailAddress", required = true) + private String emailId; + + @XmlElement(name = "RequestVersion") + private String version; + + @XmlElement(name = "DeviceType") + private String deviceType; + + public String getEmailId() { + return emailId; + } + + public String getVersion() { + return version; + } + + public void setEmailId(String emailId) { + this.emailId = emailId; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDeviceType() { + return deviceType; + } + + public void setDeviceType(String deviceType) { + this.deviceType = deviceType; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryResponse.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryResponse.java new file mode 100644 index 000000000..66d597f6a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryResponse.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans; + +import javax.xml.bind.annotation.*; +import java.io.Serializable; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "DiscoveryResponse") +@SuppressWarnings("unused") +public class DiscoveryResponse implements Serializable { + + @XmlElement(name = "AuthPolicy") + private String authPolicy; + + @XmlElement(name = "EnrollmentPolicyServiceUrl") + private String enrollmentPolicyServiceUrl; + + @XmlElement(name = "EnrollmentServiceUrl") + private String enrollmentServiceUrl; + + @XmlElement(name = "AuthenticationServiceUrl") + private String authenticationServiceUrl; + + public void setAuthenticationServiceUrl(String authenticationServiceUrl) { + this.authenticationServiceUrl = authenticationServiceUrl; + } + + public String getAuthenticationServiceUrl() { + return authenticationServiceUrl; + } + + public String getAuthPolicy() { + return authPolicy; + } + + public String getEnrollmentPolicyServiceUrl() { + return enrollmentPolicyServiceUrl; + } + + public String getEnrollmentServiceUrl() { + return enrollmentServiceUrl; + } + + public void setAuthPolicy(String authPolicy) { + this.authPolicy = authPolicy; + } + + public void setEnrollmentPolicyServiceUrl(String enrollmentPolicyServiceUrl) { + this.enrollmentPolicyServiceUrl = enrollmentPolicyServiceUrl; + } + + public void setEnrollmentServiceUrl(String enrollmentServiceUrl) { + this.enrollmentServiceUrl = enrollmentServiceUrl; + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java new file mode 100644 index 000000000..df5d15392 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java @@ -0,0 +1,22 @@ +/* +* Copyright (c) 2015, 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. +*/ + +@javax.xml.bind.annotation.XmlSchema(namespace = + "http://schemas.microsoft.com/windows/management/2012/01/enrollment", + elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package org.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans; diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/impl/DiscoveryServiceImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/impl/DiscoveryServiceImpl.java new file mode 100644 index 000000000..f15057a66 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/impl/DiscoveryServiceImpl.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.discovery.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.WindowsPluginProperties; +import org.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans.DiscoveryRequest; +import org.wso2.carbon.mdm.mobileservices.windows.services.discovery.DiscoveryService; +import org.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans.DiscoveryResponse; + +import javax.annotation.Resource; +import javax.jws.WebService; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Response; +import javax.xml.ws.BindingType; +import javax.xml.ws.Holder; +import javax.xml.ws.WebServiceContext; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.soap.Addressing; +import javax.xml.ws.soap.SOAPBinding; + +/** + * Implementation class of Discovery Request. This class implements the first two services + * of device enrolment stage. + */ +@WebService(endpointInterface = PluginConstants.DISCOVERY_SERVICE_ENDPOINT, targetNamespace = PluginConstants + .DISCOVERY_SERVICE_TARGET_NAMESPACE) +@Addressing(enabled = true, required = true) +@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) +public class DiscoveryServiceImpl implements DiscoveryService { + + public static final String FEDERATED = "Federated"; + private static Log log = LogFactory.getLog(DiscoveryServiceImpl.class); + @Resource + private WebServiceContext context; + + /** + * This method returns the OnPremise AuthPolicy and next two endpoint the mobile device should + * call if this response to received successfully at the device end. This method is called by + * device immediately after the first GET method calling for the same endpoint. + * + * @param discoveryRequest - Request bean comes via mobile phone + * @param response - DiscoveryResponse bean for response + */ + @Override + public void discover(DiscoveryRequest discoveryRequest, Holder response) { + + ServletContext ctx = (ServletContext) context.getMessageContext().get(MessageContext.SERVLET_CONTEXT); + WindowsPluginProperties windowsPluginProperties = (WindowsPluginProperties) ctx.getAttribute( + PluginConstants.WINDOWS_PLUGIN_PROPERTIES); + + DiscoveryResponse discoveryResponse = new DiscoveryResponse(); + if (FEDERATED.equals(windowsPluginProperties.getAuthPolicy())) { + discoveryResponse.setAuthPolicy(windowsPluginProperties.getAuthPolicy()); + discoveryResponse.setEnrollmentPolicyServiceUrl(PluginConstants.Discovery.ENROLL_SUBDOMAIN + + windowsPluginProperties.getDomain() + PluginConstants.Discovery. + CERTIFICATE_ENROLLMENT_POLICY_SERVICE_URL); + discoveryResponse.setEnrollmentServiceUrl(PluginConstants.Discovery.ENROLL_SUBDOMAIN + + windowsPluginProperties.getDomain() + PluginConstants.Discovery. + CERTIFICATE_ENROLLMENT_SERVICE_URL); + discoveryResponse.setAuthenticationServiceUrl(PluginConstants.Discovery.ENROLL_SUBDOMAIN + + windowsPluginProperties.getDomain() + PluginConstants.Discovery.WAB_URL); + } else { + discoveryResponse.setAuthPolicy(windowsPluginProperties.getAuthPolicy()); + discoveryResponse.setEnrollmentPolicyServiceUrl(PluginConstants.Discovery.ENROLL_SUBDOMAIN + + windowsPluginProperties.getDomain() + PluginConstants.Discovery. + ONPREMISE_CERTIFICATE_ENROLLMENT_POLICY); + discoveryResponse.setEnrollmentServiceUrl(PluginConstants.Discovery.ENROLL_SUBDOMAIN + + windowsPluginProperties.getDomain() + PluginConstants.Discovery. + ONPREMISE_CERTIFICATE_ENROLLMENT_SERVICE_URL); + discoveryResponse.setAuthenticationServiceUrl(null); + } + response.value = discoveryResponse; + + if (log.isDebugEnabled()) { + log.debug("Discovery service end point was triggered via POST method"); + } + } + + /** + * This is the first method called through device. The device checks the availability of the + * Service end point by calling this method. + * + * @return - HTTP 200OK message + */ + @Override + public Response discoverGet() { + + if (log.isDebugEnabled()) { + log.debug("Discovery service end point was triggered via GET method."); + } + return Response.ok().build(); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/policymgtservice/PolicyMgtService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/policymgtservice/PolicyMgtService.java new file mode 100644 index 000000000..cf013845f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/policymgtservice/PolicyMgtService.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.policymgtservice; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.Message; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.policy.mgt.common.Policy; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; + +import javax.jws.WebService; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; + +/** + * Endpoint for Enforce Effective Policy. + */ +@WebService +@Produces({"application/json", "application/xml"}) +@Consumes({"application/json", "application/xml"}) +public class PolicyMgtService { + private static Log log = LogFactory.getLog(PolicyMgtService.class); + + @GET + @Path("{id}") + public Message getEffectivePolicy(@HeaderParam("Accept") String acceptHeader, + @PathParam("id") String id) throws WindowsConfigurationException { + + DeviceIdentifier deviceIdentifier = WindowsAPIUtils.convertToDeviceIdentifierObject(id); + Message responseMessage = new Message(); + Policy policy; + try { + PolicyManagerService policyManagerService = WindowsAPIUtils.getPolicyManagerService(); + policy = policyManagerService.getEffectivePolicy(deviceIdentifier); + if (policy == null) { + responseMessage.setResponseCode(Response.Status.NO_CONTENT.toString()); + responseMessage.setResponseMessage("No effective policy found"); + return responseMessage; + } else { + responseMessage.setResponseCode(Response.Status.OK.toString()); + responseMessage.setResponseMessage("Effective policy added to operation"); + return responseMessage; + } + + } catch (PolicyManagementException e) { + String msg = "Error occurred while getting the policy."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/SyncmlService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/SyncmlService.java new file mode 100644 index 000000000..9e79626e8 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/SyncmlService.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml; + +import org.w3c.dom.Document; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.operations.WindowsOperationException; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Interface for Syncml message flow. + */ +@Path("/devicemanagement") +public interface SyncmlService { + + @Path("/request") + @POST + @Consumes({PluginConstants.SYNCML_MEDIA_TYPE, MediaType.APPLICATION_XML}) + @Produces(PluginConstants.SYNCML_MEDIA_TYPE) + Response getResponse(Document request) throws WindowsDeviceEnrolmentException, WindowsOperationException, + NotificationManagementException, WindowsConfigurationException; + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/BasicOperation.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/BasicOperation.java new file mode 100644 index 000000000..53d265472 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/BasicOperation.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans; + +/** + * Bean for get basic operations. + */ +public class BasicOperation { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/PasscodePolicy.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/PasscodePolicy.java new file mode 100644 index 000000000..51fc06cf4 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/PasscodePolicy.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans; + +/** + * Bean for device lockOperationUpdate screen passcode policy. + */ +public class PasscodePolicy extends BasicOperation { + + private int maxFailedAttempts; + private int minLength; + private int pinHistory; + private int minComplexChars; + private int maxPINAgeInDays; + private boolean requireAlphanumeric; + private boolean allowSimple; + private boolean enablePassword; + private int maxInactiveTime; + + public int getMaxInactiveTime() { + return maxInactiveTime; + } + + public void setMaxInactiveTime(int maxInactiveTime) { + this.maxInactiveTime = maxInactiveTime; + } + + public boolean isEnablePassword() { + return enablePassword; + } + + public void setEnablePassword(boolean enablePassword) { + this.enablePassword = enablePassword; + } + + public int getMaxFailedAttempts() { + return maxFailedAttempts; + } + + public void setMaxFailedAttempts(int maxFailedAttempts) { + this.maxFailedAttempts = maxFailedAttempts; + } + + public int getMinLength() { + return minLength; + } + + public void setMinLength(int minLength) { + this.minLength = minLength; + } + + public int getPinHistory() { + return pinHistory; + } + + public void setPinHistory(int pinHistory) { + this.pinHistory = pinHistory; + } + + public int getMinComplexChars() { + return minComplexChars; + } + + public void setMinComplexChars(int minComplexChars) { + this.minComplexChars = minComplexChars; + } + + public int getMaxPINAgeInDays() { + return maxPINAgeInDays; + } + + public void setMaxPINAgeInDays(int maxPINAgeInDays) { + this.maxPINAgeInDays = maxPINAgeInDays; + } + + public boolean isRequireAlphanumeric() { + return requireAlphanumeric; + } + + public void setRequireAlphanumeric(boolean requireAlphanumeric) { + this.requireAlphanumeric = requireAlphanumeric; + } + + public boolean isAllowSimple() { + return allowSimple; + } + + public void setAllowSimple(boolean allowSimple) { + this.allowSimple = allowSimple; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Profile.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Profile.java new file mode 100644 index 000000000..ad3a702e6 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Profile.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans; + +/** + * Class for contains device active policy. + */ +public class Profile { + + String featureCode; + String data; + boolean enable; + boolean compliance; + + public boolean isCompliance() { + return compliance; + } + + public void setCompliance(boolean compliance) { + this.compliance = compliance; + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getFeatureCode() { + return featureCode; + } + + public void setFeatureCode(String featureCode) { + this.featureCode = featureCode; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Wifi.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Wifi.java new file mode 100644 index 000000000..99979637f --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Wifi.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.beans; + +/** + * Bean for WIFI configurations. + */ +public class Wifi extends BasicOperation { + + private String networkName; + private String ssid; + private String connectionType; + private String connectionMode; + private String authentication; + private String encryption; + private String keyType; + private String protection; + private String keyMaterial; + + public String getNetworkName() { + return networkName; + } + + public void setNetworkName(String networkName) { + this.networkName = networkName; + } + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public String getConnectionType() { + return connectionType; + } + + public void setConnectionType(String connectionType) { + this.connectionType = connectionType; + } + + public String getConnectionMode() { + return connectionMode; + } + + public void setConnectionMode(String connectionMode) { + this.connectionMode = connectionMode; + } + + public String getAuthentication() { + return authentication; + } + + public void setAuthentication(String authentication) { + this.authentication = authentication; + } + + public String getEncryption() { + return encryption; + } + + public void setEncryption(String encryption) { + this.encryption = encryption; + } + + public String getKeyType() { + return keyType; + } + + public void setKeyType(String keyType) { + this.keyType = keyType; + } + + public String getProtection() { + return protection; + } + + public void setProtection(String protection) { + this.protection = protection; + } + + public String getKeyMaterial() { + return keyMaterial; + } + + public void setKeyMaterial(String keyMaterial) { + this.keyMaterial = keyMaterial; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/impl/SyncmlServiceImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/impl/SyncmlServiceImpl.java new file mode 100644 index 000000000..0a260ff75 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/impl/SyncmlServiceImpl.java @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.w3c.dom.Document; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.*; +import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.CacheEntry; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlMessageFormatException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlOperationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.DeviceUtil; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.mdm.mobileservices.windows.operations.*; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.*; +import org.wso2.carbon.mdm.mobileservices.windows.services.syncml.SyncmlService; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; + +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; + +import static org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils.convertToDeviceIdentifierObject; + +/** + * Implementing class of SyncmlImpl interface. + */ +public class SyncmlServiceImpl implements SyncmlService { + + private static Log log = LogFactory.getLog(SyncmlServiceImpl.class); + + /** + * This method is used to generate and return Device object from the received information at + * the Syncml step. + * + * @param deviceID - Unique device ID received from the Device + * @param osVersion - Device OS version + * @param imsi - Device IMSI + * @param imei - Device IMEI + * @param manufacturer - Device Manufacturer name + * @param model - Device Model + * @return - Generated device object + */ + private Device generateDevice(String type, String deviceID, String osVersion, String imsi, + String imei, String manufacturer, String model, String user) { + + Device generatedDevice = new Device(); + + Device.Property OSVersionProperty = new Device.Property(); + OSVersionProperty.setName(PluginConstants.SyncML.OS_VERSION); + OSVersionProperty.setValue(osVersion); + + Device.Property IMSEIProperty = new Device.Property(); + IMSEIProperty.setName(PluginConstants.SyncML.IMSI); + IMSEIProperty.setValue(imsi); + + Device.Property IMEIProperty = new Device.Property(); + IMEIProperty.setName(PluginConstants.SyncML.IMEI); + IMEIProperty.setValue(imei); + + Device.Property DevManProperty = new Device.Property(); + DevManProperty.setName(PluginConstants.SyncML.VENDOR); + DevManProperty.setValue(manufacturer); + + Device.Property DevModProperty = new Device.Property(); + DevModProperty.setName(PluginConstants.SyncML.MODEL); + DevModProperty.setValue(model); + + List propertyList = new ArrayList<>(); + propertyList.add(OSVersionProperty); + propertyList.add(IMSEIProperty); + propertyList.add(IMEIProperty); + propertyList.add(DevManProperty); + propertyList.add(DevModProperty); + + EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); + enrolmentInfo.setOwner(user); + enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD); + enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE); + + generatedDevice.setEnrolmentInfo(enrolmentInfo); + generatedDevice.setDeviceIdentifier(deviceID); + generatedDevice.setProperties(propertyList); + generatedDevice.setType(type); + + return generatedDevice; + } + + /** + * Method for calling SyncML engine for producing the Syncml response. For the first SyncML message comes from + * the device, this method produces a response to retrieve device information for enrolling the device. + * + * @param request - SyncML request + * @return - SyncML response + * @throws WindowsOperationException + * @throws WindowsDeviceEnrolmentException + */ + @Override + public Response getResponse(Document request) + throws WindowsDeviceEnrolmentException, WindowsOperationException, NotificationManagementException, + WindowsConfigurationException { + int msgId; + int sessionId; + String user; + String token; + String response; + SyncmlDocument syncmlDocument; + List deviceInfoOperations; + List pendingOperations; + OperationUtils operationUtils = new OperationUtils(); + DeviceInfo deviceInfo = new DeviceInfo(); + + try { + if (SyncmlParser.parseSyncmlPayload(request) != null) { + try { + syncmlDocument = SyncmlParser.parseSyncmlPayload(request); + } catch (SyncmlMessageFormatException e) { + String msg = "Error occurred due to bad syncml format."; + log.error(msg, e); + throw new SyncmlMessageFormatException(msg, e); + } + SyncmlHeader syncmlHeader = syncmlDocument.getHeader(); + sessionId = syncmlHeader.getSessionId(); + user = syncmlHeader.getSource().getLocName(); + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject(syncmlHeader.getSource() + .getLocURI()); + msgId = syncmlHeader.getMsgID(); + if ((PluginConstants.SyncML.SYNCML_FIRST_MESSAGE_ID == msgId) && + (PluginConstants.SyncML.SYNCML_FIRST_SESSION_ID == sessionId)) { + token = syncmlHeader.getCredential().getData(); + CacheEntry cacheToken = (CacheEntry) DeviceUtil.getCacheEntry(token); + + if (cacheToken.getUsername().equals(user)) { + + if (enrollDevice(request)) { + deviceInfoOperations = deviceInfo.getDeviceInfo(); + try { + response = generateReply(syncmlDocument, deviceInfoOperations); + PolicyManagerService policyManagerService = WindowsAPIUtils.getPolicyManagerService(); + policyManagerService.getEffectivePolicy(deviceIdentifier); + return Response.status(Response.Status.OK).entity(response).build(); + } catch (PolicyManagementException e) { + String msg = "Error occurred in while getting effective policy."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } catch (SyncmlOperationException e) { + String msg = "Error occurred in while generating hash value."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } + + } else { + String msg = "Error occurred in device enrollment."; + log.error(msg); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } + } else { + String msg = "Authentication failure due to incorrect credentials."; + log.error(msg); + return Response.status(Response.Status.UNAUTHORIZED).entity(msg).build(); + } + } else if (PluginConstants.SyncML.SYNCML_SECOND_MESSAGE_ID == msgId && + PluginConstants.SyncML.SYNCML_FIRST_SESSION_ID == sessionId) { + + if (enrollDevice(request)) { + try { + return Response.ok().entity(generateReply(syncmlDocument, null)).build(); + } catch (SyncmlOperationException e) { + String msg = "Error occurred in while getting effective feature"; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } + } else { + String msg = "Error occurred in modify enrollment."; + log.error(msg); + return Response.status(Response.Status.NOT_MODIFIED).entity(msg).build(); + } + } else if (sessionId >= PluginConstants.SyncML.SYNCML_SECOND_SESSION_ID) { + if ((syncmlDocument.getBody().getAlert() != null)) { + if (!syncmlDocument.getBody().getAlert().getData().equals(Constants.DISENROLL_ALERT_DATA)) { + try { + pendingOperations = operationUtils.getPendingOperations(syncmlDocument); + return Response.ok().entity(generateReply(syncmlDocument, pendingOperations)).build(); + } catch (OperationManagementException e) { + String msg = "Cannot access operation management service."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (DeviceManagementException e) { + String msg = "Cannot access Device management service."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (FeatureManagementException e) { + String msg = "Error occurred in getting effective features. "; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (PolicyComplianceException e) { + String msg = "Error occurred in setting policy compliance."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } catch (NotificationManagementException e) { + String msg = "Error occurred in while getting notification service"; + throw new WindowsOperationException(msg, e); + } catch (SyncmlOperationException e) { + String msg = "Error occurred in while encoding hash value."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } + } else { + try { + if (WindowsAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier) != null) { + WindowsAPIUtils.getDeviceManagementService().disenrollDevice(deviceIdentifier); + return Response.ok().entity(generateReply(syncmlDocument, null)).build(); + } else { + String msg = "Enrolled device can not be found in the server."; + log.error(msg); + return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); + } + } catch (DeviceManagementException e) { + String msg = "Failure occurred in dis-enrollment flow."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (SyncmlOperationException e) { + String msg = "Error occurred in while generating hash value."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } + } + } else { + try { + pendingOperations = operationUtils.getPendingOperations(syncmlDocument); + return Response.ok().entity(generateReply(syncmlDocument, pendingOperations)) + .build(); + } catch (OperationManagementException e) { + String msg = "Cannot access operation management service."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (DeviceManagementException e) { + String msg = "Cannot access Device management service."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (FeatureManagementException e) { + String msg = "Error occurred in getting effective features. "; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } catch (PolicyComplianceException e) { + String msg = "Error occurred in setting policy compliance."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } catch (NotificationManagementException e) { + String msg = "Error occurred in while getting notification service."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (SyncmlOperationException e) { + String msg = "Error occurred in while getting effective feature."; + log.error(msg, e); + throw new WindowsConfigurationException(msg, e); + } + } + } else { + String msg = "Failure occurred in Device request message."; + log.error(msg); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } + } + } catch (SyncmlMessageFormatException e) { + String msg = "Error occurred in parsing syncml request."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } + return null; + } + + /** + * Enroll phone device + * + * @param request Device syncml request for the server side. + * @return enroll state + * @throws WindowsDeviceEnrolmentException + * @throws WindowsOperationException + */ + private boolean enrollDevice(Document request) throws WindowsDeviceEnrolmentException, + WindowsOperationException { + + String osVersion; + String imsi = null; + String imei = null; + String devID; + String devMan; + String devMod; + String devLang; + String vender; + String macAddress; + String resolution; + String modVersion; + boolean status = false; + String user; + String deviceName; + int msgID; + SyncmlDocument syncmlDocument; + + try { + syncmlDocument = SyncmlParser.parseSyncmlPayload(request); + msgID = syncmlDocument.getHeader().getMsgID(); + if (msgID == PluginConstants.SyncML.SYNCML_FIRST_MESSAGE_ID) { + Replace replace = syncmlDocument.getBody().getReplace(); + List itemList = replace.getItems(); + devID = itemList.get(PluginConstants.SyncML.DEVICE_ID_POSITION).getData(); + devMan = itemList.get(PluginConstants.SyncML.DEVICE_MAN_POSITION).getData(); + devMod = itemList.get(PluginConstants.SyncML.DEVICE_MODEL_POSITION).getData(); + modVersion = itemList.get(PluginConstants.SyncML.DEVICE_MOD_VER_POSITION).getData(); + devLang = itemList.get(PluginConstants.SyncML.DEVICE_LANG_POSITION).getData(); + user = syncmlDocument.getHeader().getSource().getLocName(); + + if (log.isDebugEnabled()) { + log.debug( + "OS Version:" + modVersion + ", DevID: " + devID + ", DevMan: " + devMan + + ", DevMod: " + devMod + ", DevLang: " + devLang); + } + Device generateDevice = generateDevice(DeviceManagementConstants.MobileDeviceTypes. + MOBILE_DEVICE_TYPE_WINDOWS, devID, modVersion, imsi, imei, devMan, devMod, user); + status = WindowsAPIUtils.getDeviceManagementService().enrollDevice(generateDevice); + WindowsAPIUtils.startTenantFlow(user); + return status; + + } else if (msgID == PluginConstants.SyncML.SYNCML_SECOND_MESSAGE_ID) { + List itemList = syncmlDocument.getBody().getResults().getItem(); + osVersion = itemList.get(PluginConstants.SyncML.OSVERSION_POSITION).getData(); + imsi = itemList.get(PluginConstants.SyncML.IMSI_POSITION).getData(); + imei = itemList.get(PluginConstants.SyncML.IMEI_POSITION).getData(); + vender = itemList.get(PluginConstants.SyncML.VENDER_POSITION).getData(); + devMod = itemList.get(PluginConstants.SyncML.MODEL_POSITION).getData(); + macAddress = itemList.get(PluginConstants.SyncML.MACADDRESS_POSITION).getData(); + resolution = itemList.get(PluginConstants.SyncML.RESOLUTION_POSITION).getData(); + deviceName = itemList.get(PluginConstants.SyncML.DEVICE_NAME_POSITION).getData(); + DeviceIdentifier deviceIdentifier = convertToDeviceIdentifierObject(syncmlDocument. + getHeader().getSource().getLocURI()); + Device existingDevice = WindowsAPIUtils.getDeviceManagementService().getDevice(deviceIdentifier); + + if (!existingDevice.getProperties().isEmpty()) { + List existingProperties = new ArrayList<>(); + + Device.Property imeiProperty = new Device.Property(); + imeiProperty.setName(PluginConstants.SyncML.IMEI); + imeiProperty.setValue(imei); + existingProperties.add(imeiProperty); + + Device.Property osVersionProperty = new Device.Property(); + osVersionProperty.setName(PluginConstants.SyncML.OS_VERSION); + osVersionProperty.setValue(osVersion); + existingProperties.add(osVersionProperty); + + Device.Property imsiProperty = new Device.Property(); + imsiProperty.setName(PluginConstants.SyncML.IMSI); + imsiProperty.setValue(imsi); + existingProperties.add(imsiProperty); + + Device.Property venderProperty = new Device.Property(); + venderProperty.setName(PluginConstants.SyncML.VENDOR); + venderProperty.setValue(vender); + existingProperties.add(venderProperty); + + Device.Property macAddressProperty = new Device.Property(); + macAddressProperty.setName(PluginConstants.SyncML.MAC_ADDRESS); + macAddressProperty.setValue(macAddress); + existingProperties.add(macAddressProperty); + + Device.Property resolutionProperty = new Device.Property(); + resolutionProperty.setName(PluginConstants.SyncML.DEVICE_INFO); + resolutionProperty.setValue(resolution); + existingProperties.add(resolutionProperty); + + Device.Property deviceNameProperty = new Device.Property(); + deviceNameProperty.setName(PluginConstants.SyncML.DEVICE_NAME); + deviceNameProperty.setValue(deviceName); + existingProperties.add(deviceNameProperty); + + Device.Property deviceModelProperty = new Device.Property(); + deviceNameProperty.setName(PluginConstants.SyncML.MODEL); + deviceNameProperty.setValue(devMod); + existingProperties.add(deviceModelProperty); + + existingDevice.setProperties(existingProperties); + existingDevice.setDeviceIdentifier(syncmlDocument.getHeader().getSource().getLocURI()); + existingDevice.setType(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + status = WindowsAPIUtils.getDeviceManagementService().modifyEnrollment(existingDevice); + // call effective policy for the enrolling device. + PolicyManagerService policyManagerService = WindowsAPIUtils.getPolicyManagerService(); + policyManagerService.getEffectivePolicy(deviceIdentifier); + return status; + } + } + } catch (DeviceManagementException e) { + String msg = "Failure occurred in enrolling device."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (SyncmlMessageFormatException e) { + String msg = "Error occurred in bad format of the syncml payload."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } catch (PolicyManagementException e) { + String msg = "Error occurred in getting effective policy."; + log.error(msg, e); + throw new WindowsOperationException(msg, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + return status; + } + + /** + * Generate Device payloads. + * + * @param syncmlDocument parsed syncml payload from the syncml engine. + * @param operations operations for generate payload. + * @return String type syncml payload. + * @throws WindowsOperationException + * @throws JSONException + * @throws PolicyManagementException + * @throws org.wso2.carbon.policy.mgt.common.FeatureManagementException + */ + public String generateReply(SyncmlDocument syncmlDocument, List operations) + throws SyncmlMessageFormatException, SyncmlOperationException { + + OperationReply operationReply; + SyncmlGenerator generator; + SyncmlDocument syncmlResponse; + if (operations == null) { + operationReply = new OperationReply(syncmlDocument); + } else { + operationReply = new OperationReply(syncmlDocument, operations); + } + syncmlResponse = operationReply.generateReply(); + generator = new SyncmlGenerator(); + return generator.generatePayload(syncmlResponse); + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/PolicyManager.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/PolicyManager.java new file mode 100644 index 000000000..403b44f88 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/PolicyManager.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsConfigurationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.policy.mgt.common.Policy; +import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.core.PolicyManagerService; + +/** + * implementation for PolicyManager + */ +public class PolicyManager { + + private static Log log = LogFactory.getLog(PolicyManager.class); + + public Policy getEffectivePolicy(DeviceIdentifier deviceIdentifier) throws WindowsConfigurationException { + Policy policy; + PolicyManagerService policyManagerService = WindowsAPIUtils.getPolicyManagerService(); + try { + policy = policyManagerService.getEffectivePolicy(deviceIdentifier); + if (policy != null) { + return policy; + } else { + return null; + } + } catch (PolicyManagementException e) { + String msg = "Error occurred while getting policy."; + log.error(msg, e); + throw new WindowsConfigurationException(); + + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/SyncmlUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/SyncmlUtils.java new file mode 100644 index 000000000..90275b3cd --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/SyncmlUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.syncml.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; + +/** + * Class for generate Device object from the received data. + */ +public class SyncmlUtils { + + private static Log log = LogFactory.getLog(SyncmlUtils.class); + + /** + * This method returns Device Management Object for certain tasks such as Device enrollment etc. + * + * @return DeviceManagementServiceObject + */ + public static DeviceManagementProviderService getDeviceManagementService() { + try { + PrivilegedCarbonContext context = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + + return (DeviceManagementProviderService) context.getOSGiService(DeviceManagementProviderService.class, + null); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/CertificateEnrollmentService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/CertificateEnrollmentService.java new file mode 100644 index 000000000..e517672db --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/CertificateEnrollmentService.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WAPProvisioningException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans.AdditionalContext; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans.RequestSecurityTokenResponse; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.ws.BindingType; +import javax.xml.ws.RequestWrapper; +import javax.xml.ws.ResponseWrapper; +import javax.xml.ws.soap.SOAPBinding; +import java.io.UnsupportedEncodingException; + +/** + * Interface of WSTEP implementation. + */ +@WebService(targetNamespace = PluginConstants.DEVICE_ENROLLMENT_SERVICE_TARGET_NAMESPACE, name = "wstep") +@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) +public interface CertificateEnrollmentService { + + @RequestWrapper(localName = "RequestSecurityToken", targetNamespace = PluginConstants + .WS_TRUST_TARGET_NAMESPACE) + @WebMethod(operationName = "RequestSecurityToken") + @ResponseWrapper(localName = "RequestSecurityTokenResponseCollection", targetNamespace = + PluginConstants.WS_TRUST_TARGET_NAMESPACE) + public void requestSecurityToken( + @WebParam(name = "TokenType", targetNamespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE) + String tokenType, + @WebParam(name = "RequestType", targetNamespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE) + String requestType, + @WebParam(name = "BinarySecurityToken", targetNamespace = PluginConstants + .WS_SECURITY_TARGET_NAMESPACE) + String binarySecurityToken, + @WebParam(name = "AdditionalContext", targetNamespace = PluginConstants + .SOAP_AUTHORIZATION_TARGET_NAMESPACE) + AdditionalContext additionalContext, + @WebParam(mode = WebParam.Mode.OUT, name = "RequestSecurityTokenResponse", + targetNamespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE) + javax.xml.ws.Holder response) throws + WindowsDeviceEnrolmentException, UnsupportedEncodingException, WAPProvisioningException; +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/AdditionalContext.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/AdditionalContext.java new file mode 100644 index 000000000..8850d5afd --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/AdditionalContext.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "OIDCollection", namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE, + propOrder = {"contextitem"}) +@SuppressWarnings("unused") +public class AdditionalContext { + + @XmlElement(name = "ContextItem", required = true, + namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE) + + protected List contextitem; + + public List getcontextitem() { + if (contextitem == null) { + contextitem = new ArrayList(); + } + return this.contextitem; + } +} + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/BinarySecurityToken.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/BinarySecurityToken.java new file mode 100644 index 000000000..544c4cb79 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/BinarySecurityToken.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlValue; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "BinarySecurityToken", namespace = PluginConstants.WS_SECURITY_TARGET_NAMESPACE, + propOrder = {"ValueType", "EncodingType"}) +@SuppressWarnings("unused") +public class BinarySecurityToken { + + @XmlAttribute(name = "ValueType") + protected String ValueType; + @XmlAttribute(name = "EncodingType") + protected String EncodingType; + @XmlValue + protected String Token; + + public void setValueType(String valuetype) { + this.ValueType = valuetype; + } + + public String getValueType() { + return this.ValueType; + } + + public void setEncodingType(String encodingtype) { + this.EncodingType = encodingtype; + } + + public String getEncodingType() { + return this.EncodingType; + } + + public void setToken(String token) { + this.Token = token; + } + + public String getToken() { + return this.Token; + } + +} + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/ContextItem.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/ContextItem.java new file mode 100644 index 000000000..bfc450e55 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/ContextItem.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "ContextItem", namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE, + propOrder = {"Value"}) +public class ContextItem { + + @XmlElement(required = true, namespace = PluginConstants.SOAP_AUTHORIZATION_TARGET_NAMESPACE) + protected String Value; + + public String getValue() { + return Value; + } + + public void setValue(String value) { + Value = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityToken.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityToken.java new file mode 100644 index 000000000..74be950d1 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityToken.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "RequestedSecurityToken", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE, + propOrder = {"binarySecurityToken"}) +@SuppressWarnings("unused") +public class RequestSecurityToken { + + @XmlElement(name = "BinarySecurityToken", required = true, + namespace = PluginConstants.WS_SECURITY_TARGET_NAMESPACE) + + protected BinarySecurityToken binarySecurityToken; + + public void setBinarySecurityToken(BinarySecurityToken binarysecuritytoken) { + this.binarySecurityToken = binarysecuritytoken; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityTokenResponse.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityTokenResponse.java new file mode 100644 index 000000000..174cb0bc0 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityTokenResponse.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.io.Serializable; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "RequestSecurityTokenResponse", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE, + propOrder = {"TokenType", "RequestedSecurityToken", "RequestID"}) +@SuppressWarnings("unused") +public class RequestSecurityTokenResponse implements Serializable { + + @XmlElement(name = "TokenType", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE) + private String TokenType; + + @XmlElement(name = "RequestedSecurityToken", required = true, + namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE) + private RequestedSecurityToken RequestedSecurityToken; + + @XmlElement(name = "RequestID", namespace = PluginConstants.ENROLLMENT_POLICY_TARGET_NAMESPACE) + private int RequestID; + + public String getTokenType() { + return TokenType; + } + + public void setTokenType(String tokenType) { + TokenType = tokenType; + } + + public RequestedSecurityToken getRequestedSecurityToken() { + return RequestedSecurityToken; + } + + public void setRequestedSecurityToken(RequestedSecurityToken requestedSecurityToken) { + RequestedSecurityToken = requestedSecurityToken; + } + + public int getRequestID() { + return RequestID; + } + + public void setRequestID(int requestID) { + RequestID = requestID; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestedSecurityToken.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestedSecurityToken.java new file mode 100644 index 000000000..c448c14ce --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestedSecurityToken.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "RequestedSecurityToken", namespace = PluginConstants.WS_TRUST_TARGET_NAMESPACE, + propOrder = {"binarySecurityToken"}) +public class RequestedSecurityToken { + + @XmlElement(name = "BinarySecurityToken", required = true, + namespace = PluginConstants.WS_SECURITY_TARGET_NAMESPACE) + + protected BinarySecurityToken binarySecurityToken; + + public void setBinarySecurityToken(BinarySecurityToken binarysecuritytoken) { + this.binarySecurityToken = binarysecuritytoken; + } +} + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java new file mode 100644 index 000000000..47dd02949 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, 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. + */ + +@XmlSchema(namespace = "http://www.w3.org/2003/05/soap-envelope", + xmlns = { + @XmlNs(prefix = "", namespaceURI = "http://www.w3.org/2003/05/soap-envelope") + }, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) + +package org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; + +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlSchema; \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/impl/CertificateEnrollmentServiceImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/impl/CertificateEnrollmentServiceImpl.java new file mode 100644 index 000000000..f88600b78 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/impl/CertificateEnrollmentServiceImpl.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.impl; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.cxf.headers.Header; +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.jaxws.context.WrappedMessageContext; +import org.apache.cxf.message.Message; +import org.w3c.dom.*; +import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; +import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementServiceImpl; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.beans.CacheEntry; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.CertificateGenerationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.SyncmlMessageFormatException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WAPProvisioningException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WindowsDeviceEnrolmentException; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.DeviceUtil; +import org.wso2.carbon.mdm.mobileservices.windows.common.util.WindowsAPIUtils; +import org.wso2.carbon.mdm.mobileservices.windows.operations.util.SyncmlCredentials; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.CertificateEnrollmentService; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans.AdditionalContext; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans.BinarySecurityToken; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans.RequestSecurityTokenResponse; +import org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans.RequestedSecurityToken; +import org.xml.sax.SAXException; + +import javax.annotation.Resource; +import javax.jws.WebService; +import javax.servlet.ServletContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.ws.BindingType; +import javax.xml.ws.Holder; +import javax.xml.ws.WebServiceContext; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.soap.Addressing; +import javax.xml.ws.soap.SOAPBinding; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.List; + +/** + * Implementation class of CertificateEnrollmentService interface. This class implements MS-WSTEP + * protocol. + */ +@WebService(endpointInterface = PluginConstants.CERTIFICATE_ENROLLMENT_SERVICE_ENDPOINT, + targetNamespace = PluginConstants.DEVICE_ENROLLMENT_SERVICE_TARGET_NAMESPACE) +@Addressing(enabled = true, required = true) +@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) +public class CertificateEnrollmentServiceImpl implements CertificateEnrollmentService { + + private static final int REQUEST_ID = 0; + private static final int CA_CERTIFICATE_POSITION = 0; + private static final int SIGNED_CERTIFICATE_POSITION = 1; + private static final int APPAUTH_USERNAME_POSITION = 21; + private static final int APPAUTH_PASSWORD_POSITION = 22; + private static final int POLLING_FREQUENCY_POSITION = 27; + private static Log log = LogFactory.getLog(CertificateEnrollmentServiceImpl.class); + private X509Certificate rootCACertificate; + private String pollingFrequency; + + @Resource + private WebServiceContext context; + + /** + * This method implements MS-WSTEP for Certificate Enrollment Service. + * + * @param tokenType - Device Enrolment Token type is received via device + * @param requestType - WS-Trust request type + * @param binarySecurityToken - CSR from device + * @param additionalContext - Device type and OS version is received + * @param response - Response will include wap-provisioning xml + */ + @Override + public void requestSecurityToken(String tokenType, String requestType, + String binarySecurityToken, + AdditionalContext additionalContext, + Holder response) throws + WindowsDeviceEnrolmentException, UnsupportedEncodingException, WAPProvisioningException { + + String headerBinarySecurityToken = null; + List
      headers = getHeaders(); + for (Header headerElement : headers != null ? headers : null) { + String nodeName = headerElement.getName().getLocalPart(); + if (nodeName.equals(PluginConstants.SECURITY)) { + Element element = (Element) headerElement.getObject(); + headerBinarySecurityToken = element.getFirstChild().getNextSibling().getFirstChild().getTextContent(); + } + } + List tenantConfigurations = null; + try { + if (getTenantConfigurationData() != null) { + tenantConfigurations = getTenantConfigurationData(); + for (ConfigurationEntry configurationEntry : tenantConfigurations) { + if (configurationEntry.getName().equals(PluginConstants.TenantConfigProperties. + NOTIFIER_FREQUENCY)) { + pollingFrequency = configurationEntry.getValue().toString(); + } else { + pollingFrequency = PluginConstants.TenantConfigProperties.DEFAULT_FREQUENCY; + } + } + } else { + pollingFrequency = PluginConstants.TenantConfigProperties.DEFAULT_FREQUENCY; + String msg = "Tenant configurations are not initialized yet."; + log.error(msg); + } + } catch (DeviceManagementException e) { + String msg = "Error occurred in while getting tenant configurations."; + log.error(msg); + throw new WindowsDeviceEnrolmentException(msg, e); + } + ServletContext ctx = + (ServletContext) context.getMessageContext().get(MessageContext.SERVLET_CONTEXT); + File wapProvisioningFile = (File) ctx.getAttribute(PluginConstants.CONTEXT_WAP_PROVISIONING_FILE); + + if (log.isDebugEnabled()) { + log.debug("Received CSR from Device:" + binarySecurityToken); + } + String wapProvisioningFilePath = wapProvisioningFile.getPath(); + RequestSecurityTokenResponse requestSecurityTokenResponse = + new RequestSecurityTokenResponse(); + requestSecurityTokenResponse.setTokenType(PluginConstants.CertificateEnrolment.TOKEN_TYPE); + String encodedWap; + try { + encodedWap = prepareWapProvisioningXML(binarySecurityToken, + wapProvisioningFilePath, headerBinarySecurityToken); + RequestedSecurityToken requestedSecurityToken = new RequestedSecurityToken(); + BinarySecurityToken binarySecToken = new BinarySecurityToken(); + binarySecToken.setValueType(PluginConstants.CertificateEnrolment.VALUE_TYPE); + binarySecToken.setEncodingType(PluginConstants.CertificateEnrolment.ENCODING_TYPE); + binarySecToken.setToken(encodedWap); + requestedSecurityToken.setBinarySecurityToken(binarySecToken); + requestSecurityTokenResponse.setRequestedSecurityToken(requestedSecurityToken); + requestSecurityTokenResponse.setRequestID(REQUEST_ID); + response.value = requestSecurityTokenResponse; + } catch (CertificateGenerationException e) { + String msg = "Problem occurred in generating certificate."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (WAPProvisioningException e) { + String msg = "Problem occurred in generating wap-provisioning file."; + log.error(msg, e); + throw new WAPProvisioningException(msg, e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + /** + * Method used to Convert the Document object into a String. + * + * @param document - Wap provisioning XML document + * @return - String representation of wap provisioning XML document + * @throws TransformerException + */ + private String convertDocumentToString(Document document) throws TransformerException { + DOMSource DOMSource = new DOMSource(document); + StringWriter stringWriter = new StringWriter(); + StreamResult streamResult = new StreamResult(stringWriter); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(DOMSource, streamResult); + + return stringWriter.toString(); + } + + /** + * This method prepares the wap-provisioning file by including relevant certificates etc + * + * @param binarySecurityToken - CSR from device + * @param wapProvisioningFilePath - File path of wap-provisioning file + * @return - base64 encoded final wap-provisioning file as a String + * @throws CertificateGenerationException + * @throws org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WAPProvisioningException + */ + public String prepareWapProvisioningXML( + String binarySecurityToken, + String wapProvisioningFilePath, String headerBst) throws CertificateGenerationException, + WAPProvisioningException, WindowsDeviceEnrolmentException { + + String rootCertEncodedString; + String signedCertEncodedString; + X509Certificate signedCertificate; + + CertificateManagementServiceImpl impl = CertificateManagementServiceImpl.getInstance(); + Base64 base64Encoder = new Base64(); + try { + rootCACertificate = (X509Certificate) impl.getCACertificate(); + rootCertEncodedString = base64Encoder.encodeToString(rootCACertificate.getEncoded()); + } catch (KeystoreException e) { + String msg = "CA certificate cannot be generated"; + log.error(msg, e); + throw new CertificateGenerationException(msg, e); + } catch (CertificateEncodingException e) { + String msg = "CA certificate cannot be encoded."; + log.error(msg, e); + throw new CertificateGenerationException(msg, e); + } + + try { + signedCertificate = impl.getSignedCertificateFromCSR(binarySecurityToken); + signedCertEncodedString = base64Encoder.encodeToString(signedCertificate.getEncoded()); + } catch (CertificateEncodingException e) { + String msg = "Singed certificate cannot be encoded."; + log.error(msg, e); + throw new CertificateGenerationException(msg, e); + } catch (KeystoreException e) { + String msg = "CA certificate cannot be generated"; + log.error(msg, e); + throw new CertificateGenerationException(msg, e); + } + DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + String wapProvisioningString = null; + try { + builder = domFactory.newDocumentBuilder(); + + Document document = builder.parse(wapProvisioningFilePath); + NodeList wapParm = document.getElementsByTagName(PluginConstants.CertificateEnrolment.PARM); + Node caCertificatePosition = wapParm.item(CA_CERTIFICATE_POSITION); + + //Adding SHA1 CA certificate finger print to wap-provisioning xml. + caCertificatePosition.getParentNode().getAttributes().getNamedItem(PluginConstants. + CertificateEnrolment.TYPE).setTextContent(String.valueOf( + DigestUtils.sha512Hex(rootCACertificate.getEncoded())).toUpperCase()); + //Adding encoded CA certificate to wap-provisioning file after removing new line + // characters. + NamedNodeMap rootCertAttributes = caCertificatePosition.getAttributes(); + Node rootCertNode = + rootCertAttributes.getNamedItem(PluginConstants.CertificateEnrolment.VALUE); + rootCertEncodedString = rootCertEncodedString.replaceAll("\n", ""); + rootCertNode.setTextContent(rootCertEncodedString); + + if (log.isDebugEnabled()) { + log.debug("Root certificate: " + rootCertEncodedString); + } + + Node signedCertificatePosition = wapParm.item(SIGNED_CERTIFICATE_POSITION); + + //Adding SHA1 signed certificate finger print to wap-provisioning xml. + signedCertificatePosition.getParentNode().getAttributes().getNamedItem(PluginConstants. + CertificateEnrolment.TYPE).setTextContent(String.valueOf( + DigestUtils.sha512Hex(signedCertificate.getEncoded())).toUpperCase()); + + //Adding encoded signed certificate to wap-provisioning file after removing new line + // characters. + NamedNodeMap clientCertAttributes = signedCertificatePosition.getAttributes(); + Node clientEncodedNode = + clientCertAttributes.getNamedItem(PluginConstants.CertificateEnrolment.VALUE); + signedCertEncodedString = signedCertEncodedString.replaceAll("\n", ""); + + clientEncodedNode.setTextContent(signedCertEncodedString); + if (log.isDebugEnabled()) { + log.debug("Signed certificate: " + signedCertEncodedString); + } + + // Adding user name auth token to wap-provisioning xml + Node userNameAuthPosition = wapParm.item(APPAUTH_USERNAME_POSITION); + NamedNodeMap appServerAttribute = userNameAuthPosition.getAttributes(); + Node authNameNode = appServerAttribute.getNamedItem(PluginConstants.CertificateEnrolment.VALUE); + CacheEntry cacheEntry = (CacheEntry) DeviceUtil.getCacheEntry(headerBst); + String userName = cacheEntry.getUsername(); + authNameNode.setTextContent(cacheEntry.getUsername()); + DeviceUtil.removeToken(headerBst); + String password = DeviceUtil.generateRandomToken(); + Node passwordAuthPosition = wapParm.item(APPAUTH_PASSWORD_POSITION); + NamedNodeMap appSrvPasswordAttribute = passwordAuthPosition.getAttributes(); + Node authPasswordNode = appSrvPasswordAttribute.getNamedItem(PluginConstants.CertificateEnrolment.VALUE); + authPasswordNode.setTextContent(password); + String requestSecurityTokenResponse = new SyncmlCredentials().generateRST(userName, password); + DeviceUtil.persistChallengeToken(requestSecurityTokenResponse, null, userName); + + // Get device polling frequency from the tenant Configurations. + Node numberOfFirstRetries = wapParm.item(POLLING_FREQUENCY_POSITION); + NamedNodeMap pollingAttributes = numberOfFirstRetries.getAttributes(); + Node pollValue = pollingAttributes.getNamedItem(PluginConstants.CertificateEnrolment.VALUE); + pollValue.setTextContent(pollingFrequency); + if (log.isDebugEnabled()) { + log.debug("Username: " + userName + "Password: " + requestSecurityTokenResponse); + } + wapProvisioningString = convertDocumentToString(document); + } catch (ParserConfigurationException e) { + String msg = "Problem occurred in parsing wap-provisioning.xml file."; + log.error(msg, e); + throw new WAPProvisioningException(msg, e); + } catch (DeviceManagementException e) { + String msg = "Error occurred in while getting CA and Root certificates."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (CertificateEncodingException e) { + String msg = "Error occurred in while encoding certificates."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (UnsupportedEncodingException e) { + String msg = "Error occurred in while encoding wap-provisioning file."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } catch (SAXException e) { + String msg = "Error occurred in while parsing wap-provisioning.xml file."; + log.error(msg, e); + throw new WAPProvisioningException(msg, e); + } catch (TransformerException e) { + String msg = "Error occurred in while transforming wap-provisioning.xml file."; + log.error(msg, e); + throw new WAPProvisioningException(msg, e); + } catch (IOException e) { + String msg = "Error occurred in while getting wap-provisioning.xml file."; + log.error(msg, e); + throw new WAPProvisioningException(msg, e); + } catch (SyncmlMessageFormatException e) { + String msg = "Error occurred in while getting CA and Root certificates."; + log.error(msg, e); + throw new WindowsDeviceEnrolmentException(msg, e); + } + return base64Encoder.encodeToString(wapProvisioningString.getBytes()); + } + + /** + * This method get the soap request header contents + * + * @return Header object type,soap header tag list + */ + private List
      getHeaders() { + MessageContext messageContext = context.getMessageContext(); + if (messageContext == null || !(messageContext instanceof WrappedMessageContext)) { + return null; + } + Message message = ((WrappedMessageContext) messageContext).getWrappedMessage(); + return CastUtils.cast((List) message.get(Header.HEADER_LIST)); + } + + /** + * This method is used to get tenant configurations. + * + * @return List of Configurations entries. + * @throws DeviceManagementException + */ + private List getTenantConfigurationData() throws DeviceManagementException { + if (WindowsAPIUtils.getTenantConfiguration() != null) { + TenantConfiguration configuration = WindowsAPIUtils.getTenantConfiguration(); + return configuration.getConfiguration(); + } else { + return null; + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/CertificateSigningService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/CertificateSigningService.java new file mode 100644 index 000000000..855b96fd9 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/CertificateSigningService.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.ExtendedKeyUsage; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.KeyPurposeId; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.CertIOException; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.CertificateGenerationException; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WAPProvisioningException; + +import javax.security.auth.x500.X500Principal; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.List; + +/** + * Class for generating signed certificate for CSR form device. + */ +public class CertificateSigningService { + + private static final long MILLI_SECONDS = 1000L * 60 * 60 * 24; + + private enum PropertyIndex { + COMMON_NAME_INDEX(0), + NOT_BEFORE_DAYS_INDEX(1), + NOT_AFTER_DAYS_INDEX(2); + + private final int itemPosition; + private PropertyIndex(final int itemPosition) { + this.itemPosition = itemPosition; + } + public int getValue() { + return this.itemPosition; + } + } + + private static Log log = LogFactory.getLog(CertificateSigningService.class); + + /** + * Implement certificate signing task using CSR received from the device and the MDM server key + * store. + * @param jcaRequest - CSR from the device + * @param privateKey - Private key of CA certificate in MDM server + * @param caCert - CA certificate in MDM server + * @param certParameterList - Parameter list for Signed certificate generation + * @return - Signed certificate for CSR from device + * @throws CertificateGenerationException + * @throws org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.WAPProvisioningException + */ + public static X509Certificate signCSR(JcaPKCS10CertificationRequest jcaRequest, + PrivateKey privateKey, X509Certificate caCert, + List certParameterList) throws + CertificateGenerationException, WAPProvisioningException { + + String commonName = + (String) certParameterList.get(PropertyIndex.COMMON_NAME_INDEX.getValue()); + int notBeforeDays = + (Integer) certParameterList.get(PropertyIndex.NOT_BEFORE_DAYS_INDEX.getValue()); + int notAfterDays = + (Integer) certParameterList.get(PropertyIndex.NOT_AFTER_DAYS_INDEX.getValue()); + X509v3CertificateBuilder certificateBuilder; + X509Certificate signedCertificate; + + try { + ContentSigner signer; + BigInteger serialNumber = BigInteger.valueOf(new SecureRandom(). + nextInt(Integer.MAX_VALUE)); + Date notBeforeDate = new Date(System.currentTimeMillis() - + (MILLI_SECONDS * notBeforeDays)); + Date notAfterDate = new Date(System.currentTimeMillis() + + (MILLI_SECONDS * notAfterDays)); + certificateBuilder = + new JcaX509v3CertificateBuilder(caCert, serialNumber, notBeforeDate, notAfterDate, + new X500Principal(commonName), + jcaRequest.getPublicKey()); + + //Adding extensions to the signed certificate. + certificateBuilder.addExtension(Extension.keyUsage, true, + new KeyUsage(KeyUsage.digitalSignature)); + certificateBuilder.addExtension(Extension.extendedKeyUsage, false, + new ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth)); + certificateBuilder.addExtension(Extension.basicConstraints, true, + new BasicConstraints(false)); + + signer = new JcaContentSignerBuilder(PluginConstants.CertificateEnrolment.ALGORITHM). + setProvider(PluginConstants.CertificateEnrolment.PROVIDER).build(privateKey); + + signedCertificate = new JcaX509CertificateConverter().setProvider( + PluginConstants.CertificateEnrolment.PROVIDER).getCertificate( + certificateBuilder.build(signer)); + } catch (InvalidKeyException e) { + throw new CertificateGenerationException("CSR's public key is invalid", e); + } catch (NoSuchAlgorithmException e) { + throw new CertificateGenerationException("Certificate cannot be generated", e); + } + catch (CertIOException e) { + throw new CertificateGenerationException( + "Cannot add extension(s) to signed certificate", e); + } + catch (OperatorCreationException e) { + throw new CertificateGenerationException("Content signer cannot be created", e); + } + catch (CertificateException e) { + throw new CertificateGenerationException("Signed certificate cannot be generated", e); + } + return signedCertificate; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/KeyStoreGenerator.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/KeyStoreGenerator.java new file mode 100644 index 000000000..2e02c9faa --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/KeyStoreGenerator.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.util; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.common.exceptions.KeyStoreGenerationException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + +/** + * Class for MDM Keystore operations. + */ +public class KeyStoreGenerator { + + private static final Log log = LogFactory.getLog(KeyStoreGenerator.class); + + /** + * This method loads the MDM keystore. + * @param keyStore - MDM Keystore + * @param keyStorePassword - Keystore Password + * @param keyStorePath - Keystore path + * @throws KeyStoreGenerationException + */ + public static void loadToStore(KeyStore keyStore, + char[] keyStorePassword, + String keyStorePath) throws KeyStoreGenerationException { + + FileInputStream fileInputStream = null; + + try { + if (keyStorePath != null) { + fileInputStream = new FileInputStream(keyStorePath); + keyStore.load(fileInputStream, keyStorePassword); + } + } catch (NoSuchAlgorithmException e) { + throw new KeyStoreGenerationException( + "Requested cryptographic algorithm is not available in the environment.", e); + } catch (CertificateException e) { + throw new KeyStoreGenerationException("Error working with certificate related to, " + + keyStorePath, e); + } catch (IOException e) { + throw new KeyStoreGenerationException("File error while working with file, " + + keyStorePath, e); + } finally { + try { + if (fileInputStream != null) { + fileInputStream.close(); + } + } catch (IOException e) { + throw new KeyStoreGenerationException("File error while closing the file, " + + keyStorePath,e); + } + } + } + + /** + * This method is for retrieving instance of Key Store. + * @return Keystore object + * @throws KeyStoreGenerationException + */ + public static KeyStore getKeyStore() throws KeyStoreGenerationException { + try { + return KeyStore.getInstance(PluginConstants.CertificateEnrolment.JKS); + } catch (KeyStoreException e) { + String msg = "KeyStore error while creating new JKS."; + log.error(msg, e); + throw new KeyStoreGenerationException(msg, e); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/MessageHandler.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/MessageHandler.java new file mode 100644 index 000000000..9d4ae0118 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/MessageHandler.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.wstep.util; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; + +import javax.ws.rs.core.Response; +import javax.xml.namespace.QName; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.xml.soap.Name; +import javax.xml.soap.SOAPEnvelope; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPFactory; +import javax.xml.soap.SOAPHeader; +import javax.xml.soap.SOAPHeaderElement; +import javax.xml.soap.SOAPMessage; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.soap.SOAPHandler; +import javax.xml.ws.handler.soap.SOAPMessageContext; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.*; + +/** + * Class responsible for adding Timestamp security header in SOAP message and adding Content-length + * in the HTTP header for avoiding HTTP chunking. + */ +public class MessageHandler implements SOAPHandler { + + public static final String TIME_ZONE = "Z"; + public static final int VALIDITY_TIME = 5; + public static final int TIMESTAMP_END_INDEX = 6; + public static final int TIMESTAMP_BEGIN_INDEX = 0; + private static Log log = LogFactory.getLog(MessageHandler.class); + + /** + * This method resolves the security header coming in the SOAP message. + * @return - Security Header + */ + @Override + public Set getHeaders() { + QName securityHeader = new QName(PluginConstants.WS_SECURITY_TARGET_NAMESPACE, PluginConstants.SECURITY); + HashSet headers = new HashSet(); + headers.add(securityHeader); + return headers; + } + + /** + * This method adds Timestamp for SOAP header, and adds Content-length for HTTP header for + * avoiding HTTP chunking. + * + * @param context - Context of the SOAP Message + */ + @Override + public boolean handleMessage(SOAPMessageContext context) { + + Boolean outBoundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); + + if (outBoundProperty) { + SOAPMessage message = context.getMessage(); + SOAPHeader header = null; + SOAPEnvelope envelope = null; + try { + header = message.getSOAPHeader(); + envelope = message.getSOAPPart().getEnvelope(); + } catch (SOAPException e) { + Response.serverError().entity("SOAP message content cannot be read.").build(); + } + try { + if ((header == null) && (envelope != null)) { + header = envelope.addHeader(); + } + } catch (SOAPException e) { + Response.serverError().entity("SOAP header cannot be added.").build(); + } + + SOAPFactory soapFactory = null; + try { + soapFactory = SOAPFactory.newInstance(); + } catch (SOAPException e) { + Response.serverError().entity("Cannot get an instance of SOAP factory.").build(); + } + + QName qNamesSecurity = new QName(PluginConstants.WS_SECURITY_TARGET_NAMESPACE, + PluginConstants.CertificateEnrolment.SECURITY); + SOAPHeaderElement Security = null; + Name attributeName = null; + try { + if (header != null) { + Security = header.addHeaderElement(qNamesSecurity); + } + if (soapFactory != null) { + attributeName = + soapFactory.createName(PluginConstants.CertificateEnrolment.TIMESTAMP_ID, + PluginConstants.CertificateEnrolment.TIMESTAMP_U, + PluginConstants.CertificateEnrolment + .WSS_SECURITY_UTILITY); + } + } catch (SOAPException e) { + Response.serverError().entity("Security header cannot be added.").build(); + } + + QName qNameTimestamp = new QName(PluginConstants.CertificateEnrolment.WSS_SECURITY_UTILITY, + PluginConstants.CertificateEnrolment.TIMESTAMP); + SOAPHeaderElement timestamp = null; + try { + if (header != null) { + timestamp = header.addHeaderElement(qNameTimestamp); + timestamp.addAttribute(attributeName, + PluginConstants.CertificateEnrolment.TIMESTAMP_0); + } + } catch (SOAPException e) { + Response.serverError().entity("Exception while adding timestamp header.").build(); + } + DateTime dateTime = new DateTime(); + DateTime expiredDateTime = dateTime.plusMinutes(VALIDITY_TIME); + String createdISOTime = dateTime.toString(ISODateTimeFormat.dateTime()); + String expiredISOTime = expiredDateTime.toString(ISODateTimeFormat.dateTime()); + createdISOTime = createdISOTime.substring(TIMESTAMP_BEGIN_INDEX, + createdISOTime.length() - + TIMESTAMP_END_INDEX); + createdISOTime = createdISOTime + TIME_ZONE; + expiredISOTime = expiredISOTime.substring(TIMESTAMP_BEGIN_INDEX, + expiredISOTime.length() - + TIMESTAMP_END_INDEX); + expiredISOTime = expiredISOTime + TIME_ZONE; + QName qNameCreated = new QName(PluginConstants.CertificateEnrolment.WSS_SECURITY_UTILITY, + PluginConstants.CertificateEnrolment.CREATED); + SOAPHeaderElement SOAPHeaderCreated = null; + + try { + if (header != null) { + SOAPHeaderCreated = header.addHeaderElement(qNameCreated); + SOAPHeaderCreated.addTextNode(createdISOTime); + } + } catch (SOAPException e) { + Response.serverError().entity("Exception while creating SOAP header.").build(); + } + QName qNameExpires = new QName(PluginConstants.CertificateEnrolment.WSS_SECURITY_UTILITY, + PluginConstants.CertificateEnrolment.EXPIRES); + SOAPHeaderElement SOAPHeaderExpires = null; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + String messageString = null; + try { + if (header != null) { + SOAPHeaderExpires = header.addHeaderElement(qNameExpires); + SOAPHeaderExpires.addTextNode(expiredISOTime); + } + if ((timestamp != null) && (Security != null)) { + timestamp.addChildElement(SOAPHeaderCreated); + timestamp.addChildElement(SOAPHeaderExpires); + Security.addChildElement(timestamp); + } + message.saveChanges(); + message.writeTo(outputStream); + messageString = new String(outputStream.toByteArray(), + PluginConstants.CertificateEnrolment.UTF_8); + } catch (SOAPException e) { + Response.serverError().entity("Exception while creating timestamp SOAP header.") + .build(); + } catch (IOException e) { + Response.serverError().entity("Exception while writing message to output stream.") + .build(); + } + + Map> headers = + (Map>) context.get(MessageContext.HTTP_REQUEST_HEADERS); + headers = new HashMap>(); + if (messageString != null) { + headers.put(PluginConstants.CONTENT_LENGTH, Arrays.asList(String.valueOf( + messageString.length()))); + } + context.put(MessageContext.HTTP_REQUEST_HEADERS, headers); + } + return true; + } + + @Override + public boolean handleFault(SOAPMessageContext context) { + return true; + } + + @Override + public void close(MessageContext context) { + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/CertificateEnrollmentPolicyService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/CertificateEnrollmentPolicyService.java new file mode 100644 index 000000000..8e08c0529 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/CertificateEnrollmentPolicyService.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep; + +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.CACollection; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.Client; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.OIDCollection; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.ObjectFactory; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.RequestFilter; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.Response; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.BindingType; +import javax.xml.ws.Holder; +import javax.xml.ws.RequestWrapper; +import javax.xml.ws.ResponseWrapper; +import javax.xml.ws.soap.SOAPBinding; + +/** + * Interface for MS-XCEP implementation. + */ +@WebService(targetNamespace = PluginConstants.CERTIFICATE_ENROLLMENT_POLICY_SERVICE_TARGET_NAMESPACE, + name = "IPolicy") +@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) +@XmlSeeAlso({ ObjectFactory.class }) +public interface CertificateEnrollmentPolicyService { + + @RequestWrapper(localName = "GetPolicies", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE, className = PluginConstants.REQUEST_WRAPPER_CLASS_NAME) + @WebMethod(operationName = "GetPolicies") + @ResponseWrapper(localName = "GetPoliciesResponse", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE, className = PluginConstants. + RESPONSE_WRAPPER_CLASS_NAME) void getPolicies( + @WebParam(name = "client", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE) + Client client, + @WebParam(name = "requestFilter", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE) + RequestFilter requestFilter, + @WebParam(mode = WebParam.Mode.OUT, name = "response", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE) + Holder response, + @WebParam(mode = WebParam.Mode.OUT, name = "cAs", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE) + Holder caCollection, + @WebParam(mode = WebParam.Mode.OUT, name = "oIDs", targetNamespace = PluginConstants. + ENROLLMENT_POLICY_TARGET_NAMESPACE) + Holder oidCollection + ); +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Attributes.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Attributes.java new file mode 100644 index 000000000..e39ba5c98 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Attributes.java @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for Attributes complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="Attributes">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element ref="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}commonName"/>
      + *         <element name="policySchema" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="certificateValidity" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CertificateValidity"/>
      + *         <element name="permission" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}EnrollmentPermission"/>
      + *         <element name="privateKeyAttributes" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}PrivateKeyAttributes"/>
      + *         <element name="revision" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}Revision"/>
      + *         <element name="supersededPolicies" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}SupersededPolicies"/>
      + *         <element name="privateKeyFlags" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="subjectNameFlags" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="enrollmentFlags" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="generalFlags" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="hashAlgorithmOIDReference" type="{http://www.w3
      + *         .org/2001/XMLSchema}int"/>
      + *         <element name="rARequirements" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}RARequirements"/>
      + *         <element name="keyArchivalAttributes" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}KeyArchivalAttributes"/>
      + *         <element name="extensions" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}ExtensionCollection"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Attributes", propOrder = { + "commonName", + "policySchema", + "certificateValidity", + "permission", + "privateKeyAttributes", + "revision", + "supersededPolicies", + "privateKeyFlags", + "subjectNameFlags", + "enrollmentFlags", + "generalFlags", + "hashAlgorithmOIDReference", + "raRequirements", + "keyArchivalAttributes", + "extensions", + "any" +}) +@SuppressWarnings("unused") +public class Attributes { + + @XmlElement(required = true) + protected String commonName; + @XmlSchemaType(name = "unsignedInt") + protected long policySchema; + @XmlElement(required = true) + protected CertificateValidity certificateValidity; + @XmlElement(required = true) + protected EnrollmentPermission permission; + @XmlElement(required = true) + protected PrivateKeyAttributes privateKeyAttributes; + @XmlElement(required = true) + protected Revision revision; + @XmlElement(required = true, nillable = true) + protected SupersededPolicies supersededPolicies; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long privateKeyFlags; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long subjectNameFlags; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long enrollmentFlags; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long generalFlags; + @XmlElement(required = true, type = Integer.class, nillable = true) + protected Integer hashAlgorithmOIDReference; + @XmlElement(name = "rARequirements", required = true, nillable = true) + protected RARequirements raRequirements; + @XmlElement(required = true, nillable = true) + protected KeyArchivalAttributes keyArchivalAttributes; + @XmlElement(required = true, nillable = true) + protected ExtensionCollection extensions; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the commonName property. + * + * @return possible object is + * {@link String } + */ + public String getCommonName() { + return commonName; + } + + /** + * Sets the value of the commonName property. + * + * @param value allowed object is + * {@link String } + */ + public void setCommonName(String value) { + this.commonName = value; + } + + /** + * Gets the value of the policySchema property. + */ + public long getPolicySchema() { + return policySchema; + } + + /** + * Sets the value of the policySchema property. + */ + public void setPolicySchema(long value) { + this.policySchema = value; + } + + /** + * Gets the value of the certificateValidity property. + * + * @return possible object is + * {@link CertificateValidity } + */ + public CertificateValidity getCertificateValidity() { + return certificateValidity; + } + + /** + * Sets the value of the certificateValidity property. + * + * @param value allowed object is + * {@link CertificateValidity } + */ + public void setCertificateValidity(CertificateValidity value) { + this.certificateValidity = value; + } + + /** + * Gets the value of the permission property. + * + * @return possible object is + * {@link EnrollmentPermission } + */ + public EnrollmentPermission getPermission() { + return permission; + } + + /** + * Sets the value of the permission property. + * + * @param value allowed object is + * {@link EnrollmentPermission } + */ + public void setPermission(EnrollmentPermission value) { + this.permission = value; + } + + /** + * Gets the value of the privateKeyAttributes property. + * + * @return possible object is + * {@link PrivateKeyAttributes } + */ + public PrivateKeyAttributes getPrivateKeyAttributes() { + return privateKeyAttributes; + } + + /** + * Sets the value of the privateKeyAttributes property. + * + * @param value allowed object is + * {@link PrivateKeyAttributes } + */ + public void setPrivateKeyAttributes(PrivateKeyAttributes value) { + this.privateKeyAttributes = value; + } + + /** + * Gets the value of the revision property. + * + * @return possible object is + * {@link Revision } + */ + public Revision getRevision() { + return revision; + } + + /** + * Sets the value of the revision property. + * + * @param value allowed object is + * {@link Revision } + */ + public void setRevision(Revision value) { + this.revision = value; + } + + /** + * Gets the value of the supersededPolicies property. + * + * @return possible object is + * {@link SupersededPolicies } + */ + public SupersededPolicies getSupersededPolicies() { + return supersededPolicies; + } + + /** + * Sets the value of the supersededPolicies property. + * + * @param value allowed object is + * {@link SupersededPolicies } + */ + public void setSupersededPolicies(SupersededPolicies value) { + this.supersededPolicies = value; + } + + /** + * Gets the value of the privateKeyFlags property. + * + * @return possible object is + * {@link Long } + */ + public Long getPrivateKeyFlags() { + return privateKeyFlags; + } + + /** + * Sets the value of the privateKeyFlags property. + * + * @param value allowed object is + * {@link Long } + */ + public void setPrivateKeyFlags(Long value) { + this.privateKeyFlags = value; + } + + /** + * Gets the value of the subjectNameFlags property. + * + * @return possible object is + * {@link Long } + */ + public Long getSubjectNameFlags() { + return subjectNameFlags; + } + + /** + * Sets the value of the subjectNameFlags property. + * + * @param value allowed object is + * {@link Long } + */ + public void setSubjectNameFlags(Long value) { + this.subjectNameFlags = value; + } + + /** + * Gets the value of the enrollmentFlags property. + * + * @return possible object is + * {@link Long } + */ + public Long getEnrollmentFlags() { + return enrollmentFlags; + } + + /** + * Sets the value of the enrollmentFlags property. + * + * @param value allowed object is + * {@link Long } + */ + public void setEnrollmentFlags(Long value) { + this.enrollmentFlags = value; + } + + /** + * Gets the value of the generalFlags property. + * + * @return possible object is + * {@link Long } + */ + public Long getGeneralFlags() { + return generalFlags; + } + + /** + * Sets the value of the generalFlags property. + * + * @param value allowed object is + * {@link Long } + */ + public void setGeneralFlags(Long value) { + this.generalFlags = value; + } + + /** + * Gets the value of the hashAlgorithmOIDReference property. + * + * @return possible object is + * {@link Integer } + */ + public Integer getHashAlgorithmOIDReference() { + return hashAlgorithmOIDReference; + } + + /** + * Sets the value of the hashAlgorithmOIDReference property. + * + * @param value allowed object is + * {@link Integer } + */ + public void setHashAlgorithmOIDReference(Integer value) { + this.hashAlgorithmOIDReference = value; + } + + /** + * Gets the value of the raRequirements property. + * + * @return possible object is + * {@link RARequirements } + */ + public RARequirements getRARequirements() { + return raRequirements; + } + + /** + * Sets the value of the raRequirements property. + * + * @param value allowed object is + * {@link RARequirements } + */ + public void setRARequirements(RARequirements value) { + this.raRequirements = value; + } + + /** + * Gets the value of the keyArchivalAttributes property. + * + * @return possible object is + * {@link KeyArchivalAttributes } + */ + public KeyArchivalAttributes getKeyArchivalAttributes() { + return keyArchivalAttributes; + } + + /** + * Sets the value of the keyArchivalAttributes property. + * + * @param value allowed object is + * {@link KeyArchivalAttributes } + */ + public void setKeyArchivalAttributes(KeyArchivalAttributes value) { + this.keyArchivalAttributes = value; + } + + /** + * Gets the value of the extensions property. + * + * @return possible object is + * {@link ExtensionCollection } + */ + public ExtensionCollection getExtensions() { + return extensions; + } + + /** + * Sets the value of the extensions property. + * + * @param value allowed object is + * {@link ExtensionCollection } + */ + public void setExtensions(ExtensionCollection value) { + this.extensions = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CA.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CA.java new file mode 100644 index 000000000..4b643f089 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CA.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CA complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CA">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="uris" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CAURICollection"/>
      + *         <element name="certificate" type="{http://www.w3.org/2001/XMLSchema}base64Binary"/>
      + *         <element name="enrollPermission" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *         <element name="cAReferenceID" type="{http://www.w3.org/2001/XMLSchema}int"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CA", propOrder = { + "uris", + "certificate", + "enrollPermission", + "caReferenceID", + "any" +}) +@SuppressWarnings("unused") +public class CA { + + @XmlElement(required = true) + protected CAURICollection uris; + @XmlElement(required = true) + protected byte[] certificate; + protected boolean enrollPermission; + @XmlElement(name = "cAReferenceID") + protected int caReferenceID; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the uris property. + * + * @return possible object is + * {@link CAURICollection } + */ + public CAURICollection getUris() { + return uris; + } + + /** + * Sets the value of the uris property. + * + * @param value allowed object is + * {@link CAURICollection } + */ + public void setUris(CAURICollection value) { + this.uris = value; + } + + /** + * Gets the value of the certificate property. + * + * @return possible object is + * byte[] + */ + public byte[] getCertificate() { + return certificate; + } + + /** + * Sets the value of the certificate property. + * + * @param value allowed object is + * byte[] + */ + public void setCertificate(byte[] value) { + this.certificate = value; + } + + /** + * Gets the value of the enrollPermission property. + */ + public boolean isEnrollPermission() { + return enrollPermission; + } + + /** + * Sets the value of the enrollPermission property. + */ + public void setEnrollPermission(boolean value) { + this.enrollPermission = value; + } + + /** + * Gets the value of the caReferenceID property. + */ + public int getCAReferenceID() { + return caReferenceID; + } + + /** + * Sets the value of the caReferenceID property. + */ + public void setCAReferenceID(int value) { + this.caReferenceID = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CACollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CACollection.java new file mode 100644 index 000000000..cc94b04db --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CACollection.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CACollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CACollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="cA" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CA" maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CACollection", propOrder = { + "ca" +}) +@SuppressWarnings("unused") +public class CACollection { + + @XmlElement(name = "cA", required = true) + protected List ca; + + /** + * Gets the value of the ca property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the ca property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getCA().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link CA } + */ + public List getCA() { + if (ca == null) { + ca = new ArrayList(); + } + return this.ca; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAReferenceCollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAReferenceCollection.java new file mode 100644 index 000000000..6199b4ee3 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAReferenceCollection.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CAReferenceCollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CAReferenceCollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="cAReference" type="{http://www.w3.org/2001/XMLSchema}int"
      + *         maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CAReferenceCollection", propOrder = { + "caReference" +}) +@SuppressWarnings("unused") +public class CAReferenceCollection { + + @XmlElement(name = "cAReference", type = Integer.class) + protected List caReference; + + /** + * Gets the value of the caReference property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the caReference property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getCAReference().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Integer } + */ + public List getCAReference() { + if (caReference == null) { + caReference = new ArrayList(); + } + return this.caReference; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURI.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURI.java new file mode 100644 index 000000000..ee33ba079 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURI.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CAURI complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CAURI">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="clientAuthentication" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="uri" type="{http://www.w3.org/2001/XMLSchema}anyURI"/>
      + *         <element name="priority" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="renewalOnly" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CAURI", propOrder = { + "clientAuthentication", + "uri", + "priority", + "renewalOnly", + "any" +}) +@SuppressWarnings("unused") +public class CAURI { + + @XmlSchemaType(name = "unsignedInt") + protected long clientAuthentication; + @XmlElement(required = true) + @XmlSchemaType(name = "anyURI") + protected String uri; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long priority; + protected boolean renewalOnly; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the clientAuthentication property. + */ + public long getClientAuthentication() { + return clientAuthentication; + } + + /** + * Sets the value of the clientAuthentication property. + */ + public void setClientAuthentication(long value) { + this.clientAuthentication = value; + } + + /** + * Gets the value of the uri property. + * + * @return possible object is + * {@link String } + */ + public String getUri() { + return uri; + } + + /** + * Sets the value of the uri property. + * + * @param value allowed object is + * {@link String } + */ + public void setUri(String value) { + this.uri = value; + } + + /** + * Gets the value of the priority property. + * + * @return possible object is + * {@link Long } + */ + public Long getPriority() { + return priority; + } + + /** + * Sets the value of the priority property. + * + * @param value allowed object is + * {@link Long } + */ + public void setPriority(Long value) { + this.priority = value; + } + + /** + * Gets the value of the renewalOnly property. + */ + public boolean isRenewalOnly() { + return renewalOnly; + } + + /** + * Sets the value of the renewalOnly property. + */ + public void setRenewalOnly(boolean value) { + this.renewalOnly = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURICollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURICollection.java new file mode 100644 index 000000000..6278311da --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURICollection.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CAURICollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CAURICollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="cAURI" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CAURI" maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CAURICollection", propOrder = { + "cauri" +}) +@SuppressWarnings("unused") +public class CAURICollection { + + @XmlElement(name = "cAURI", required = true) + protected List cauri; + + /** + * Gets the value of the cauri property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the cauri property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getCAURI().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link CAURI } + */ + public List getCAURI() { + if (cauri == null) { + cauri = new ArrayList(); + } + return this.cauri; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateEnrollmentPolicy.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateEnrollmentPolicy.java new file mode 100644 index 000000000..4ce348190 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateEnrollmentPolicy.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CertificateEnrollmentPolicy complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CertificateEnrollmentPolicy">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="policyOIDReference" type="{http://www.w3.org/2001/XMLSchema}int"/>
      + *         <element name="cAs" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CAReferenceCollection"/>
      + *         <element name="attributes" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}Attributes"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CertificateEnrollmentPolicy", propOrder = { + "policyOIDReference", + "cAs", + "attributes", + "any" +}) +@SuppressWarnings("unused") +public class CertificateEnrollmentPolicy { + + protected int policyOIDReference; + @XmlElement(required = true, nillable = true) + protected CAReferenceCollection cAs; + @XmlElement(required = true) + protected Attributes attributes; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the policyOIDReference property. + */ + public int getPolicyOIDReference() { + return policyOIDReference; + } + + /** + * Sets the value of the policyOIDReference property. + */ + public void setPolicyOIDReference(int value) { + this.policyOIDReference = value; + } + + /** + * Gets the value of the cAs property. + * + * @return possible object is + * {@link CAReferenceCollection } + */ + public CAReferenceCollection getCAs() { + return cAs; + } + + /** + * Sets the value of the cAs property. + * + * @param value allowed object is + * {@link CAReferenceCollection } + */ + public void setCAs(CAReferenceCollection value) { + this.cAs = value; + } + + /** + * Gets the value of the attributes property. + * + * @return possible object is + * {@link Attributes } + */ + public Attributes getAttributes() { + return attributes; + } + + /** + * Sets the value of the attributes property. + * + * @param value allowed object is + * {@link Attributes } + */ + public void setAttributes(Attributes value) { + this.attributes = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateValidity.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateValidity.java new file mode 100644 index 000000000..41d77542c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateValidity.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.*; +import java.math.BigInteger; + +/** + *

      Java class for CertificateValidity complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CertificateValidity">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="validityPeriodSeconds" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedLong"/>
      + *         <element name="renewalPeriodSeconds" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedLong"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CertificateValidity", propOrder = { + "validityPeriodSeconds", + "renewalPeriodSeconds" +}) +@SuppressWarnings("unused") +public class CertificateValidity { + + @XmlElement(required = true) + @XmlSchemaType(name = "unsignedLong") + protected BigInteger validityPeriodSeconds; + @XmlElement(required = true) + @XmlSchemaType(name = "unsignedLong") + protected BigInteger renewalPeriodSeconds; + + /** + * Gets the value of the validityPeriodSeconds property. + * + * @return possible object is + * {@link BigInteger } + */ + public BigInteger getValidityPeriodSeconds() { + return validityPeriodSeconds; + } + + /** + * Sets the value of the validityPeriodSeconds property. + * + * @param value allowed object is + * {@link BigInteger } + */ + public void setValidityPeriodSeconds(BigInteger value) { + this.validityPeriodSeconds = value; + } + + /** + * Gets the value of the renewalPeriodSeconds property. + * + * @return possible object is + * {@link BigInteger } + */ + public BigInteger getRenewalPeriodSeconds() { + return renewalPeriodSeconds; + } + + /** + * Sets the value of the renewalPeriodSeconds property. + * + * @param value allowed object is + * {@link BigInteger } + */ + public void setRenewalPeriodSeconds(BigInteger value) { + this.renewalPeriodSeconds = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Client.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Client.java new file mode 100644 index 000000000..685bfd522 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Client.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.datatype.XMLGregorianCalendar; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for Client complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="Client">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="lastUpdate" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
      + *         <element name="preferredLanguage" type="{http://www.w3.org/2001/XMLSchema}language"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Client", propOrder = { + "lastUpdate", + "preferredLanguage", + "any" +}) +@SuppressWarnings("unused") +public class Client { + + @XmlElement(required = true, nillable = true) + @XmlSchemaType(name = "dateTime") + protected XMLGregorianCalendar lastUpdate; + @XmlElement(required = true, nillable = true) + @XmlJavaTypeAdapter(CollapsedStringAdapter.class) + @XmlSchemaType(name = "language") + protected String preferredLanguage; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the lastUpdate property. + * + * @return possible object is + * {@link XMLGregorianCalendar } + */ + public XMLGregorianCalendar getLastUpdate() { + return lastUpdate; + } + + /** + * Sets the value of the lastUpdate property. + * + * @param value allowed object is + * {@link XMLGregorianCalendar } + */ + public void setLastUpdate(XMLGregorianCalendar value) { + this.lastUpdate = value; + } + + /** + * Gets the value of the preferredLanguage property. + * + * @return possible object is + * {@link String } + */ + public String getPreferredLanguage() { + return preferredLanguage; + } + + /** + * Sets the value of the preferredLanguage property. + * + * @param value allowed object is + * {@link String } + */ + public void setPreferredLanguage(String value) { + this.preferredLanguage = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CryptoProviders.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CryptoProviders.java new file mode 100644 index 000000000..d483b7c47 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CryptoProviders.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for CryptoProviders complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="CryptoProviders">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="provider" type="{http://www.w3.org/2001/XMLSchema}string"
      + *         maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CryptoProviders", propOrder = { + "provider" +}) +@SuppressWarnings("unused") +public class CryptoProviders { + + @XmlElement(required = true) + protected List provider; + + /** + * Instantiate provider list in the constructor + */ + public CryptoProviders() { + this.provider = new ArrayList(); + } + + /** + * Gets the value of the provider property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the provider property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getProvider().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link String } + */ + public List getProvider() { + return this.provider; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/EnrollmentPermission.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/EnrollmentPermission.java new file mode 100644 index 000000000..3a05b9d28 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/EnrollmentPermission.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for EnrollmentPermission complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="EnrollmentPermission">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="enroll" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *         <element name="autoEnroll" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "EnrollmentPermission", propOrder = { + "enroll", + "autoEnroll" +}) +@SuppressWarnings("unused") +public class EnrollmentPermission { + + protected boolean enroll; + protected boolean autoEnroll; + + /** + * Gets the value of the enroll property. + */ + public boolean isEnroll() { + return enroll; + } + + /** + * Sets the value of the enroll property. + */ + public void setEnroll(boolean value) { + this.enroll = value; + } + + /** + * Gets the value of the autoEnroll property. + */ + public boolean isAutoEnroll() { + return autoEnroll; + } + + /** + * Sets the value of the autoEnroll property. + */ + public void setAutoEnroll(boolean value) { + this.autoEnroll = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Extension.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Extension.java new file mode 100644 index 000000000..7647d853a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Extension.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for Extension complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="Extension">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="oIDReference" type="{http://www.w3.org/2001/XMLSchema}int"/>
      + *         <element name="critical" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}base64Binary"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Extension", propOrder = { + "oidReference", + "critical", + "value" +}) +@SuppressWarnings("unused") +public class Extension { + + @XmlElement(name = "oIDReference") + protected int oidReference; + protected boolean critical; + @XmlElement(required = true, nillable = true) + protected byte[] value; + + /** + * Gets the value of the oidReference property. + */ + public int getOIDReference() { + return oidReference; + } + + /** + * Sets the value of the oidReference property. + */ + public void setOIDReference(int value) { + this.oidReference = value; + } + + /** + * Gets the value of the critical property. + */ + public boolean isCritical() { + return critical; + } + + /** + * Sets the value of the critical property. + */ + public void setCritical(boolean value) { + this.critical = value; + } + + /** + * Gets the value of the value property. + * + * @return possible object is + * byte[] + */ + public byte[] getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value allowed object is + * byte[] + */ + public void setValue(byte[] value) { + this.value = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ExtensionCollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ExtensionCollection.java new file mode 100644 index 000000000..4e5422cbc --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ExtensionCollection.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for ExtensionCollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="ExtensionCollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="extension" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}Extension" maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "ExtensionCollection", propOrder = { + "extension" +}) +@SuppressWarnings("unused") +public class ExtensionCollection { + + @XmlElement(required = true) + protected List extension; + + /** + * Instantiate extension list in the constructor + */ + public ExtensionCollection() { + this.extension = new ArrayList(); + } + + /** + * Gets the value of the extension property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the extension property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getExtension().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Extension } + */ + public List getExtension() { + return this.extension; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/FilterOIDCollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/FilterOIDCollection.java new file mode 100644 index 000000000..a50dc51f2 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/FilterOIDCollection.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for FilterOIDCollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="FilterOIDCollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="oid" type="{http://www.w3.org/2001/XMLSchema}string"
      + *         maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "FilterOIDCollection", propOrder = { + "oid" +}) +@SuppressWarnings("unused") +public class FilterOIDCollection { + + @XmlElement(required = true) + protected List oid; + + /** + * Instantiate oid list in the constructor + */ + public FilterOIDCollection() { + this.oid = new ArrayList(); + } + + /** + * Gets the value of the oid property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the oid property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getOid().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link String } + */ + public List getOid() { + return this.oid; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPolicies.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPolicies.java new file mode 100644 index 000000000..c312533f6 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPolicies.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for anonymous complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType>
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="client" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}Client"/>
      + *         <element name="requestFilter" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}RequestFilter"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "client", + "requestFilter" +}) +@XmlRootElement(name = "GetPolicies") +@SuppressWarnings("unused") +public class GetPolicies { + + @XmlElement(required = true) + protected Client client; + @XmlElement(required = true, nillable = true) + protected RequestFilter requestFilter; + + /** + * Gets the value of the client property. + * + * @return possible object is + * {@link Client } + */ + public Client getClient() { + return client; + } + + /** + * Sets the value of the client property. + * + * @param value allowed object is + * {@link Client } + */ + public void setClient(Client value) { + this.client = value; + } + + /** + * Gets the value of the requestFilter property. + * + * @return possible object is + * {@link RequestFilter } + */ + public RequestFilter getRequestFilter() { + return requestFilter; + } + + /** + * Sets the value of the requestFilter property. + * + * @param value allowed object is + * {@link RequestFilter } + */ + public void setRequestFilter(RequestFilter value) { + this.requestFilter = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPoliciesResponse.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPoliciesResponse.java new file mode 100644 index 000000000..d15b4c8b8 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPoliciesResponse.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for anonymous complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType>
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="response" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}Response"/>
      + *         <element name="cAs" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CACollection"/>
      + *         <element name="oIDs" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}OIDCollection"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "response", + "cAs", + "oiDs" +}) +@XmlRootElement(name = "GetPoliciesResponse") +@SuppressWarnings("unused") +public class GetPoliciesResponse { + + @XmlElement(required = true, nillable = true) + protected Response response; + @XmlElement(required = true, nillable = true) + protected CACollection cAs; + @XmlElement(name = "oIDs", required = true, nillable = true) + protected OIDCollection oiDs; + + /** + * Gets the value of the response property. + * + * @return possible object is + * {@link Response } + */ + public Response getResponse() { + return response; + } + + /** + * Sets the value of the response property. + * + * @param value allowed object is + * {@link Response } + */ + public void setResponse(Response value) { + this.response = value; + } + + /** + * Gets the value of the cAs property. + * + * @return possible object is + * {@link CACollection } + */ + public CACollection getCAs() { + return cAs; + } + + /** + * Sets the value of the cAs property. + * + * @param value allowed object is + * {@link CACollection } + */ + public void setCAs(CACollection value) { + this.cAs = value; + } + + /** + * Gets the value of the oiDs property. + * + * @return possible object is + * {@link OIDCollection } + */ + public OIDCollection getOIDs() { + return oiDs; + } + + /** + * Sets the value of the oiDs property. + * + * @param value allowed object is + * {@link OIDCollection } + */ + public void setOIDs(OIDCollection value) { + this.oiDs = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/KeyArchivalAttributes.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/KeyArchivalAttributes.java new file mode 100644 index 000000000..d48ebb386 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/KeyArchivalAttributes.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for KeyArchivalAttributes complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="KeyArchivalAttributes">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="symmetricAlgorithmOIDReference" type="{http://www.w3
      + *         .org/2001/XMLSchema}int"/>
      + *         <element name="symmetricAlgorithmKeyLength" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedInt"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "KeyArchivalAttributes", propOrder = { + "symmetricAlgorithmOIDReference", + "symmetricAlgorithmKeyLength" +}) +@SuppressWarnings("unused") +public class KeyArchivalAttributes { + + protected int symmetricAlgorithmOIDReference; + @XmlSchemaType(name = "unsignedInt") + protected long symmetricAlgorithmKeyLength; + + /** + * Gets the value of the symmetricAlgorithmOIDReference property. + */ + public int getSymmetricAlgorithmOIDReference() { + return symmetricAlgorithmOIDReference; + } + + /** + * Sets the value of the symmetricAlgorithmOIDReference property. + */ + public void setSymmetricAlgorithmOIDReference(int value) { + this.symmetricAlgorithmOIDReference = value; + } + + /** + * Gets the value of the symmetricAlgorithmKeyLength property. + */ + public long getSymmetricAlgorithmKeyLength() { + return symmetricAlgorithmKeyLength; + } + + /** + * Sets the value of the symmetricAlgorithmKeyLength property. + */ + public void setSymmetricAlgorithmKeyLength(long value) { + this.symmetricAlgorithmKeyLength = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OID.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OID.java new file mode 100644 index 000000000..7415bc68a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OID.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for OID complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="OID">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="value" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="group" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="oIDReferenceID" type="{http://www.w3.org/2001/XMLSchema}int"/>
      + *         <element name="defaultName" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "OID", propOrder = { + "value", + "group", + "oidReferenceID", + "defaultName", + "any" +}) +@SuppressWarnings("unused") +public class OID { + + @XmlElement(required = true) + protected String value; + @XmlSchemaType(name = "unsignedInt") + protected long group; + @XmlElement(name = "oIDReferenceID") + protected int oidReferenceID; + @XmlElement(required = true, nillable = true) + protected String defaultName; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the value property. + * + * @return possible object is + * {@link String } + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value allowed object is + * {@link String } + */ + public void setValue(String value) { + this.value = value; + } + + /** + * Gets the value of the group property. + */ + public long getGroup() { + return group; + } + + /** + * Sets the value of the group property. + */ + public void setGroup(long value) { + this.group = value; + } + + /** + * Gets the value of the oidReferenceID property. + */ + public int getOIDReferenceID() { + return oidReferenceID; + } + + /** + * Sets the value of the oidReferenceID property. + */ + public void setOIDReferenceID(int value) { + this.oidReferenceID = value; + } + + /** + * Gets the value of the defaultName property. + * + * @return possible object is + * {@link String } + */ + public String getDefaultName() { + return defaultName; + } + + /** + * Sets the value of the defaultName property. + * + * @param value allowed object is + * {@link String } + */ + public void setDefaultName(String value) { + this.defaultName = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDCollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDCollection.java new file mode 100644 index 000000000..54861d807 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDCollection.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for OIDCollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="OIDCollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="oID" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}OID" maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "OIDCollection", propOrder = { + "oid" +}) +@SuppressWarnings("unused") +public class OIDCollection { + + @XmlElement(name = "oID", required = true) + protected List oid; + + /** + * Gets the value of the oid property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the oid property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getOID().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link OID } + */ + public List getOID() { + if (oid == null) { + oid = new ArrayList(); + } + return this.oid; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDReferenceCollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDReferenceCollection.java new file mode 100644 index 000000000..9d095532e --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDReferenceCollection.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for OIDReferenceCollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="OIDReferenceCollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="oIDReference" type="{http://www.w3.org/2001/XMLSchema}int"
      + *         maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "OIDReferenceCollection", propOrder = { + "oidReference" +}) +@SuppressWarnings("unused") +public class OIDReferenceCollection { + + @XmlElement(name = "oIDReference", type = Integer.class) + protected List oidReference; + + /** + * Gets the value of the oidReference property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the oidReference property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getOIDReference().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Integer } + */ + public List getOIDReference() { + if (oidReference == null) { + oidReference = new ArrayList(); + } + return this.oidReference; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ObjectFactory.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ObjectFactory.java new file mode 100644 index 000000000..83db64243 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ObjectFactory.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the com.microsoft.schemas.windows.pki._2009._01.enrollmentpolicy package. + *

      An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + */ +@XmlRegistry +@SuppressWarnings("unused") +public class ObjectFactory { + + private final static QName _CommonName_QNAME = + new QName("http://schemas.microsoft.com/windows/pki/2009/01/enrollmentpolicy", + "commonName"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived + * classes for package: com.microsoft.schemas.windows.pki._2009._01.enrollmentpolicy + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link GetPolicies } + */ + public GetPolicies createGetPolicies() { + return new GetPolicies(); + } + + /** + * Create an instance of {@link Client } + */ + public Client createClient() { + return new Client(); + } + + /** + * Create an instance of {@link RequestFilter } + */ + public RequestFilter createRequestFilter() { + return new RequestFilter(); + } + + /** + * Create an instance of {@link GetPoliciesResponse } + */ + public GetPoliciesResponse createGetPoliciesResponse() { + return new GetPoliciesResponse(); + } + + /** + * Create an instance of {@link Response } + */ + public Response createResponse() { + return new Response(); + } + + /** + * Create an instance of {@link CACollection } + */ + public CACollection createCACollection() { + return new CACollection(); + } + + /** + * Create an instance of {@link OIDCollection } + */ + public OIDCollection createOIDCollection() { + return new OIDCollection(); + } + + /** + * Create an instance of {@link SupersededPolicies } + */ + public SupersededPolicies createSupersededPolicies() { + return new SupersededPolicies(); + } + + /** + * Create an instance of {@link OID } + */ + public OID createOID() { + return new OID(); + } + + /** + * Create an instance of {@link ExtensionCollection } + */ + public ExtensionCollection createExtensionCollection() { + return new ExtensionCollection(); + } + + /** + * Create an instance of {@link Attributes } + */ + public Attributes createAttributes() { + return new Attributes(); + } + + /** + * Create an instance of {@link EnrollmentPermission } + */ + public EnrollmentPermission createEnrollmentPermission() { + return new EnrollmentPermission(); + } + + /** + * Create an instance of {@link CAReferenceCollection } + */ + public CAReferenceCollection createCAReferenceCollection() { + return new CAReferenceCollection(); + } + + /** + * Create an instance of {@link CertificateValidity } + */ + public CertificateValidity createCertificateValidity() { + return new CertificateValidity(); + } + + /** + * Create an instance of {@link CAURICollection } + */ + public CAURICollection createCAURICollection() { + return new CAURICollection(); + } + + /** + * Create an instance of {@link PolicyCollection } + */ + public PolicyCollection createPolicyCollection() { + return new PolicyCollection(); + } + + /** + * Create an instance of {@link Revision } + */ + public Revision createRevision() { + return new Revision(); + } + + /** + * Create an instance of {@link OIDReferenceCollection } + */ + public OIDReferenceCollection createOIDReferenceCollection() { + return new OIDReferenceCollection(); + } + + /** + * Create an instance of {@link CA } + */ + public CA createCA() { + return new CA(); + } + + /** + * Create an instance of {@link CertificateEnrollmentPolicy } + */ + public CertificateEnrollmentPolicy createCertificateEnrollmentPolicy() { + return new CertificateEnrollmentPolicy(); + } + + /** + * Create an instance of {@link CryptoProviders } + */ + public CryptoProviders createCryptoProviders() { + return new CryptoProviders(); + } + + /** + * Create an instance of {@link Extension } + */ + public Extension createExtension() { + return new Extension(); + } + + /** + * Create an instance of {@link FilterOIDCollection } + */ + public FilterOIDCollection createFilterOIDCollection() { + return new FilterOIDCollection(); + } + + /** + * Create an instance of {@link CAURI } + */ + public CAURI createCAURI() { + return new CAURI(); + } + + /** + * Create an instance of {@link RARequirements } + */ + public RARequirements createRARequirements() { + return new RARequirements(); + } + + /** + * Create an instance of {@link PrivateKeyAttributes } + */ + public PrivateKeyAttributes createPrivateKeyAttributes() { + return new PrivateKeyAttributes(); + } + + /** + * Create an instance of {@link KeyArchivalAttributes } + */ + public KeyArchivalAttributes createKeyArchivalAttributes() { + return new KeyArchivalAttributes(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}} + */ + @XmlElementDecl(namespace = + "http://schemas.microsoft.com/windows/pki/2009/01/enrollmentpolicy" + + "", name = "commonName") + public JAXBElement createCommonName(String value) { + return new JAXBElement(_CommonName_QNAME, String.class, null, value); + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PolicyCollection.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PolicyCollection.java new file mode 100644 index 000000000..2dbb7f7e0 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PolicyCollection.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for PolicyCollection complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="PolicyCollection">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="policy" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CertificateEnrollmentPolicy"
      + *         maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "PolicyCollection", propOrder = { + "policy" +}) +@SuppressWarnings("unused") +public class PolicyCollection { + + @XmlElement(required = true) + protected List policy; + + /** + * Gets the value of the policy property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the policy property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getPolicy().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link CertificateEnrollmentPolicy } + */ + public List getPolicy() { + if (policy == null) { + policy = new ArrayList(); + } + return this.policy; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PrivateKeyAttributes.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PrivateKeyAttributes.java new file mode 100644 index 000000000..9ecd50ecf --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PrivateKeyAttributes.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for PrivateKeyAttributes complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="PrivateKeyAttributes">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="minimalKeyLength" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="keySpec" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="keyUsageProperty" type="{http://www.w3
      + *         .org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="permissions" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="algorithmOIDReference" type="{http://www.w3.org/2001/XMLSchema}int"/>
      + *         <element name="cryptoProviders" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}CryptoProviders"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "PrivateKeyAttributes", propOrder = { + "minimalKeyLength", + "keySpec", + "keyUsageProperty", + "permissions", + "algorithmOIDReference", + "cryptoProviders" +}) +@SuppressWarnings("unused") +public class PrivateKeyAttributes { + + @XmlSchemaType(name = "unsignedInt") + protected long minimalKeyLength; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long keySpec; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long keyUsageProperty; + @XmlElement(required = true, nillable = true) + protected String permissions; + @XmlElement(required = true, type = Integer.class, nillable = true) + protected Integer algorithmOIDReference; + @XmlElement(required = true, nillable = true) + protected CryptoProviders cryptoProviders; + + /** + * Gets the value of the minimalKeyLength property. + */ + public long getMinimalKeyLength() { + return minimalKeyLength; + } + + /** + * Sets the value of the minimalKeyLength property. + */ + public void setMinimalKeyLength(long value) { + this.minimalKeyLength = value; + } + + /** + * Gets the value of the keySpec property. + * + * @return possible object is + * {@link Long } + */ + public Long getKeySpec() { + return keySpec; + } + + /** + * Sets the value of the keySpec property. + * + * @param value allowed object is + * {@link Long } + */ + public void setKeySpec(Long value) { + this.keySpec = value; + } + + /** + * Gets the value of the keyUsageProperty property. + * + * @return possible object is + * {@link Long } + */ + public Long getKeyUsageProperty() { + return keyUsageProperty; + } + + /** + * Sets the value of the keyUsageProperty property. + * + * @param value allowed object is + * {@link Long } + */ + public void setKeyUsageProperty(Long value) { + this.keyUsageProperty = value; + } + + /** + * Gets the value of the permissions property. + * + * @return possible object is + * {@link String } + */ + public String getPermissions() { + return permissions; + } + + /** + * Sets the value of the permissions property. + * + * @param value allowed object is + * {@link String } + */ + public void setPermissions(String value) { + this.permissions = value; + } + + /** + * Gets the value of the algorithmOIDReference property. + * + * @return possible object is + * {@link Integer } + */ + public Integer getAlgorithmOIDReference() { + return algorithmOIDReference; + } + + /** + * Sets the value of the algorithmOIDReference property. + * + * @param value allowed object is + * {@link Integer } + */ + public void setAlgorithmOIDReference(Integer value) { + this.algorithmOIDReference = value; + } + + /** + * Gets the value of the cryptoProviders property. + * + * @return possible object is + * {@link CryptoProviders } + */ + public CryptoProviders getCryptoProviders() { + return cryptoProviders; + } + + /** + * Sets the value of the cryptoProviders property. + * + * @param value allowed object is + * {@link CryptoProviders } + */ + public void setCryptoProviders(CryptoProviders value) { + this.cryptoProviders = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RARequirements.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RARequirements.java new file mode 100644 index 000000000..d5ff3788b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RARequirements.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for RARequirements complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="RARequirements">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="rASignatures" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="rAEKUs" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}OIDReferenceCollection"/>
      + *         <element name="rAPolicies" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}OIDReferenceCollection"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "RARequirements", propOrder = { + "raSignatures", + "raekUs", + "raPolicies" +}) +@SuppressWarnings("unused") +public class RARequirements { + + @XmlElement(name = "rASignatures") + @XmlSchemaType(name = "unsignedInt") + protected long raSignatures; + @XmlElement(name = "rAEKUs", required = true, nillable = true) + protected OIDReferenceCollection raekUs; + @XmlElement(name = "rAPolicies", required = true, nillable = true) + protected OIDReferenceCollection raPolicies; + + /** + * Gets the value of the raSignatures property. + */ + public long getRASignatures() { + return raSignatures; + } + + /** + * Sets the value of the raSignatures property. + */ + public void setRASignatures(long value) { + this.raSignatures = value; + } + + /** + * Gets the value of the raekUs property. + * + * @return possible object is + * {@link OIDReferenceCollection } + */ + public OIDReferenceCollection getRAEKUs() { + return raekUs; + } + + /** + * Sets the value of the raekUs property. + * + * @param value allowed object is + * {@link OIDReferenceCollection } + */ + public void setRAEKUs(OIDReferenceCollection value) { + this.raekUs = value; + } + + /** + * Gets the value of the raPolicies property. + * + * @return possible object is + * {@link OIDReferenceCollection } + */ + public OIDReferenceCollection getRAPolicies() { + return raPolicies; + } + + /** + * Sets the value of the raPolicies property. + * + * @param value allowed object is + * {@link OIDReferenceCollection } + */ + public void setRAPolicies(OIDReferenceCollection value) { + this.raPolicies = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RequestFilter.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RequestFilter.java new file mode 100644 index 000000000..b1e419806 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RequestFilter.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for RequestFilter complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="RequestFilter">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="policyOIDs" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}FilterOIDCollection"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "RequestFilter", propOrder = { + "policyOIDs", + "any" +}) +@SuppressWarnings("unused") +public class RequestFilter { + + @XmlElement(required = true, nillable = true) + protected FilterOIDCollection policyOIDs; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the policyOIDs property. + * + * @return possible object is + * {@link FilterOIDCollection } + */ + public FilterOIDCollection getPolicyOIDs() { + return policyOIDs; + } + + /** + * Sets the value of the policyOIDs property. + * + * @param value allowed object is + * {@link FilterOIDCollection } + */ + public void setPolicyOIDs(FilterOIDCollection value) { + this.policyOIDs = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Response.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Response.java new file mode 100644 index 000000000..90246f03c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Response.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.*; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for Response complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="Response">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="policyID" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="policyFriendlyName" type="{http://www.w3.org/2001/XMLSchema}string"/>
      + *         <element name="nextUpdateHours" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="policiesNotChanged" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
      + *         <element name="policies" type="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}PolicyCollection"/>
      + *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Response", propOrder = { + "policyID", + "policyFriendlyName", + "nextUpdateHours", + "policiesNotChanged", + "policies", + "any" +}) +@SuppressWarnings("unused") +public class Response { + + @XmlElement(required = true) + protected String policyID; + @XmlElement(required = true, nillable = true) + protected String policyFriendlyName; + @XmlElement(required = true, type = Long.class, nillable = true) + @XmlSchemaType(name = "unsignedInt") + protected Long nextUpdateHours; + @XmlElement(required = true, type = Boolean.class, nillable = true) + protected Boolean policiesNotChanged; + @XmlElement(required = true, nillable = true) + protected PolicyCollection policies; + @XmlAnyElement(lax = true) + protected List any; + + /** + * Gets the value of the policyID property. + * + * @return possible object is + * {@link String } + */ + public String getPolicyID() { + return policyID; + } + + /** + * Sets the value of the policyID property. + * + * @param value allowed object is + * {@link String } + */ + public void setPolicyID(String value) { + this.policyID = value; + } + + /** + * Gets the value of the policyFriendlyName property. + * + * @return possible object is + * {@link String } + */ + public String getPolicyFriendlyName() { + return policyFriendlyName; + } + + /** + * Sets the value of the policyFriendlyName property. + * + * @param value allowed object is + * {@link String } + */ + public void setPolicyFriendlyName(String value) { + this.policyFriendlyName = value; + } + + /** + * Gets the value of the nextUpdateHours property. + * + * @return possible object is + * {@link Long } + */ + public Long getNextUpdateHours() { + return nextUpdateHours; + } + + /** + * Sets the value of the nextUpdateHours property. + * + * @param value allowed object is + * {@link Long } + */ + public void setNextUpdateHours(Long value) { + this.nextUpdateHours = value; + } + + /** + * Gets the value of the policiesNotChanged property. + * + * @return possible object is + * {@link Boolean } + */ + public Boolean isPoliciesNotChanged() { + return policiesNotChanged; + } + + /** + * Sets the value of the policiesNotChanged property. + * + * @param value allowed object is + * {@link Boolean } + */ + public void setPoliciesNotChanged(Boolean value) { + this.policiesNotChanged = value; + } + + /** + * Gets the value of the policies property. + * + * @return possible object is + * {@link PolicyCollection } + */ + public PolicyCollection getPolicies() { + return policies; + } + + /** + * Sets the value of the policies property. + * + * @param value allowed object is + * {@link PolicyCollection } + */ + public void setPolicies(PolicyCollection value) { + this.policies = value; + } + + /** + * Gets the value of the any property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the any property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getAny().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link Object } + * {@link Element } + */ + public List getAny() { + if (any == null) { + any = new ArrayList(); + } + return this.any; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Revision.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Revision.java new file mode 100644 index 000000000..e838b4b26 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Revision.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +/** + *

      Java class for Revision complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="Revision">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element name="majorRevision" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *         <element name="minorRevision" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Revision", propOrder = { + "majorRevision", + "minorRevision" +}) +@SuppressWarnings("unused") +public class Revision { + + @XmlSchemaType(name = "unsignedInt") + protected long majorRevision; + @XmlSchemaType(name = "unsignedInt") + protected long minorRevision; + + /** + * Gets the value of the majorRevision property. + */ + public long getMajorRevision() { + return majorRevision; + } + + /** + * Sets the value of the majorRevision property. + */ + public void setMajorRevision(long value) { + this.majorRevision = value; + } + + /** + * Gets the value of the minorRevision property. + */ + public long getMinorRevision() { + return minorRevision; + } + + /** + * Sets the value of the minorRevision property. + */ + public void setMinorRevision(long value) { + this.minorRevision = value; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/SupersededPolicies.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/SupersededPolicies.java new file mode 100644 index 000000000..722950cea --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/SupersededPolicies.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; + +/** + *

      Java class for SupersededPolicies complex type. + *

      + *

      The following schema fragment specifies the expected content contained within this class. + *

      + *

      + * <complexType name="SupersededPolicies">
      + *   <complexContent>
      + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      + *       <sequence>
      + *         <element ref="{http://schemas.microsoft
      + *         .com/windows/pki/2009/01/enrollmentpolicy}commonName" maxOccurs="unbounded"/>
      + *       </sequence>
      + *     </restriction>
      + *   </complexContent>
      + * </complexType>
      + * 
      + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "SupersededPolicies", propOrder = { + "commonName" +}) +@SuppressWarnings("unused") +public class SupersededPolicies { + + @XmlElement(required = true) + protected List commonName; + + /** + * Gets the value of the commonName property. + *

      + *

      + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the commonName property. + *

      + *

      + * For example, to add a new item, do as follows: + *

      +	 *    getCommonName().add(newItem);
      +	 * 
      + *

      + *

      + *

      + * Objects of the following type(s) are allowed in the list + * {@link String } + */ + public List getCommonName() { + if (commonName == null) { + commonName = new ArrayList(); + } + return this.commonName; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java new file mode 100644 index 000000000..f3c0f5b58 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015, 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. + */ + +@javax.xml.bind.annotation.XmlSchema(namespace = "http://schemas.microsoft" + + ".com/windows/pki/2009/01/enrollmentpolicy", + elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) + +package org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/impl/CertificateEnrollmentPolicyServiceImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/impl/CertificateEnrollmentPolicyServiceImpl.java new file mode 100644 index 000000000..25d909f92 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/impl/CertificateEnrollmentPolicyServiceImpl.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.mdm.mobileservices.windows.services.xcep.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.mdm.mobileservices.windows.common.PluginConstants; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.CertificateEnrollmentPolicyService; +import org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans.*; + +import javax.jws.WebService; +import javax.xml.ws.BindingType; +import javax.xml.ws.Holder; +import javax.xml.ws.soap.Addressing; +import javax.xml.ws.soap.SOAPBinding; + +/** + * Implementation class for CertificateEnrollmentPolicyService. + */ +@WebService(endpointInterface = PluginConstants.CERTIFICATE_ENROLLMENT_POLICY_SERVICE_ENDPOINT, + targetNamespace = PluginConstants.CERTIFICATE_ENROLLMENT_POLICY_SERVICE_TARGET_NAMESPACE) +@Addressing(enabled = true, required = true) +@BindingType(value = SOAPBinding.SOAP12HTTP_BINDING) +public class CertificateEnrollmentPolicyServiceImpl implements CertificateEnrollmentPolicyService { + + private static Log log = LogFactory.getLog(CertificateEnrollmentPolicyServiceImpl.class); + + /** + * This method implements the MS-XCEP protocol for certificate enrollment policy service. + * + * @param client - Included lastUpdate and preferredLanguage tags + * @param requestFilter - Policy constrain tag + * @param response - Response which includes minimal key length, hash algorithm, policy + * schema, policy OID reference + * @param caCollection - Contains the issuers for the certificate enrollment policies + * @param oidCollection - Contains the collection of OIDs for the response + */ + @Override + public void getPolicies(Client client, RequestFilter requestFilter, + Holder response, Holder caCollection, + Holder oidCollection) { + + if (log.isDebugEnabled()) { + log.debug("Enrolment certificate policy end point was triggered by device."); + } + + Response responseElement = new Response(); + OIDCollection oidCollectionElement = new OIDCollection(); + CACollection caCollectionElement = new CACollection(); + + PolicyCollection policyCollectionElement = new PolicyCollection(); + + CertificateEnrollmentPolicy certEnrollmentPolicyElement = new CertificateEnrollmentPolicy(); + Attributes attributeElement = new Attributes(); + PrivateKeyAttributes privateKeyAttributeElement = new PrivateKeyAttributes(); + + privateKeyAttributeElement. + setMinimalKeyLength(PluginConstants.CertificateEnrolmentPolicy.MINIMAL_KEY_LENGTH); + + attributeElement.setPolicySchema(PluginConstants.CertificateEnrolmentPolicy.POLICY_SCHEMA); + attributeElement.setPrivateKeyAttributes(privateKeyAttributeElement); + attributeElement.setHashAlgorithmOIDReference(PluginConstants.CertificateEnrolmentPolicy. + HASH_ALGORITHM_OID_REFERENCE); + certEnrollmentPolicyElement.setPolicyOIDReference(PluginConstants.CertificateEnrolmentPolicy. + OID_REFERENCE); + certEnrollmentPolicyElement.setAttributes(attributeElement); + policyCollectionElement.getPolicy().add(certEnrollmentPolicyElement); + responseElement.setPolicies(policyCollectionElement); + response.value = responseElement; + + OID oidElement = new OID(); + oidElement.setValue(PluginConstants.CertificateEnrolmentPolicy.OID); + oidElement.setGroup(PluginConstants.CertificateEnrolmentPolicy.OID_GROUP); + oidElement.setOIDReferenceID(PluginConstants.CertificateEnrolmentPolicy.OID_REFERENCE_ID); + oidElement.setDefaultName(PluginConstants.CertificateEnrolmentPolicy.OID_DEFAULT_NAME); + + oidCollectionElement.getOID().add(oidElement); + caCollection.value = caCollectionElement; + oidCollection.value = oidCollectionElement; + + PrivilegedCarbonContext.endTenantFlow(); + + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml new file mode 100644 index 000000000..7df287f68 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml @@ -0,0 +1,26 @@ + + + Federated + wso2carbon + cacert + CN=mdmcn + 3 + 300 + wso2.com + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml new file mode 100644 index 000000000..e6729e0f4 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wso2mdm.jks b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wso2mdm.jks new file mode 100644 index 0000000000000000000000000000000000000000..66b68ea395562b9716c8c579b944ae19b5dbf296 GIT binary patch literal 9485 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 W`0v%-2|WuF22km0Do6xx&3^&4V5S-X literal 0 HcmV?d00001 diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 000000000..feb34b098 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,142 @@ + + + + + + + + + Lock + /device-mgt/windows/operation/lock + /services/windows/operation/lock + POST + emm_admin,emm_user + + + + Enterprise Wipe + /device-mgt/windows/operation/wipe-data + /services/windows/operation/wipe-data + POST + emm_admin + + + + Ring + /device-mgt/windows/operation/ring-device + /services/windows/operation/ring-device + POST + emm_admin,emm_user + + + + Disenroll + /device-mgt/windows/operation/disenroll + /services/windows/operation/disenroll + POST + emm_admin,emm_user + + + + LockReset + /device-mgt/windows/operation/lock-reset + /services/windows/operation/lock-reset + POST + emm_admin,emm_user + + + + + Get CSR Policy + /device-mgt/windows/devices/getPolicy + /services/certificatepolicy/xcep + POST + emm_windows_agent + + + Get BST + /device-mgt/windows/devices/getBST + /services/federated/bst/authentication + POST + emm_windows_agent + + + Provide CSR + /device-mgt/windows/devices/requestSecurityToken + /services/deviceenrolment/wstep + POST + emm_windows_agent + + + GetLicense + /device-mgt/windows/devices/license + /services/device/license + GET + emm_windows_agent + + + + View Policies + /device-mgt/windows/policies/view + /services/policy/* + GET + emm_admin + + + + View Policy Features + /device-mgt/windows/policies/view + /services/policy/features/* + GET + emm_admin + + + + View Tenant configuration + /device-mgt/windows/tenant/configuration + /services/configuration + GET + emm_admin + + + + Add Tenant configuration + /device-mgt/windows/tenant/configuration + /services/configuration + POST + emm_admin + + + + Update Tenant configuration + /device-mgt/windows/tenant/configuration + /services/configuration + PUT + emm_admin + + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 000000000..0371f7c29 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + Carbon + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 000000000..23cd504ba --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/web.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..93b441ed4 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,63 @@ + + + + Windows-Agent-Webapp + + + contextConfigLocation + /WEB-INF/cxf-servlet.xml + + + + org.wso2.carbon.mdm.mobileservices.windows.common.util.ConfigInitializerContextListener + + + + + JAX-WS/JAX-RS-windows Endpoint + JAX-WS/JAX-RS-windows Servlet + JAXServlet-windows + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + JAXServlet-windows + /services/* + + + 60 + + + + doAuthentication + true + + + nonSecuredEndPoints + /services/discovery/get,/services/discovery/post,/services/certificatepolicy/xcep, + ,/services/deviceenrolment/wstep,/services/syncml/devicemanagement/request + + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/servicelist.css b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/servicelist.css new file mode 100644 index 000000000..e6eacadbb --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/servicelist.css @@ -0,0 +1,125 @@ +@CHARSET "ISO-8859-1"; + +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +html { + background: #efefef; +} + +body { + line-height: 1; + width: 960px; + margin: auto; + background: white; + padding: 10px; + box-shadow: 0px 0px 5px #CCC; + font-family: "Lucida Grande", "Lucida Sans", "Microsoft Sans Serif", "Lucida Sans Unicode", "Verdana", "Sans-serif", "trebuchet ms" !important; + +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; + width: 960px; + border: solid 1px #ccc; +} + +table a { + font-size: 12px; + color: #1e90ff; + padding: 7px; + float: left;; +} + +.heading { + font-size: 18px; + margin-top: 20px; + float: left; + color: #0067B1; + margin-bottom: 20px; + padding-top: 20px; +} + +.field { + font-weight: normal; + width: 120px; + font-size: 12px; + float: left; + padding: 7px; + clear: left; +} + +.value { + font-weight: bold; + font-size: 12px; + float: left; + padding: 7px; + clear: right; +} + +.porttypename { + font-weight: bold; + font-size: 14px; +} + +UL { + margin-top: 0; +} + +LI { + font-weight: normal; + font-size: 12px; + margin-top: 10px; +} + +TD { + border: 1px solid #ccc; + vertical-align: text-top; + padding: 5px; +} + + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/pom.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/pom.xml new file mode 100644 index 000000000..2440f0fff --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/pom.xml @@ -0,0 +1,176 @@ + + + + + + + windows-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.windows + bundle + WSO2 Carbon - Mobile Device Management Windows Impl + WSO2 Carbon - Mobile Device Management Windows Implementation + http://wso2.org + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + 1.4.0 + true + + + ${project.artifactId} + ${project.artifactId} + ${carbon.devicemgt.plugins.version} + Device Management Mobile Windows Impl Bundle + org.wso2.carbon.device.mgt.mobile.windows.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.xml.bind.*, + javax.naming, + javax.sql, + javax.xml.bind.annotation.*, + javax.xml.parsers.*;resolution:=optional, + org.w3c.dom, + org.wso2.carbon.core, + org.wso2.carbon.context, + org.wso2.carbon.utils.*, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.device.mgt.mobile.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.policy.mgt.common.*, + org.wso2.carbon.policy.mgt.core.*, + org.wso2.carbon.registry.core, + org.wso2.carbon.registry.core.exceptions, + org.wso2.carbon.registry.core.service, + org.wso2.carbon.registry.core.session, + org.wso2.carbon.registry.api, + org.wso2.carbon.device.mgt.extensions.license.mgt.registry, + com.google.gson.* + + + !org.wso2.carbon.device.mgt.mobile.windows.internal, + org.wso2.carbon.device.mgt.mobile.windows.* + + + + + + + + + + + + + + + + + + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.carbon + org.wso2.carbon.core + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.extensions + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.policy.mgt.core + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + org.wso2.carbon + org.wso2.carbon.registry.core + + + org.testng + testng + + + org.apache.tomcat.wso2 + jdbc-pool + + + com.h2database.wso2 + h2-database-engine + test + + + com.google.code.gson + gson + + + diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java new file mode 100644 index 000000000..36d3bb963 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl; + +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; + +/** + * This represents the Windows implementation of DeviceManagerService. + */ +public class WindowsDeviceManagementService implements DeviceManagementService { + + private DeviceManager deviceManager; + public static final String DEVICE_TYPE_WINDOWS = "windows"; + public static final String DEVICE_TYPE_TENANT = "carbon.super"; + + @Override + public String getType() { + return WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS; + } + + @Override + public String getProviderTenantDomain() { + return DEVICE_TYPE_TENANT; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public void init() throws DeviceManagementException { + this.deviceManager = new WindowsDeviceManager(); + } + + @Override + public DeviceManager getDeviceManager() { + return deviceManager; + } + + @Override + public ApplicationManager getApplicationManager() { + return null; + } + + @Override public void notifyOperationToDevices(Operation operation, List deviceIdentifiers) + throws DeviceManagementException { + + } + + @Override + public Application[] getApplications(String s, int i, int i2) throws ApplicationManagementException { + return new Application[0]; + } + + @Override + public void updateApplicationStatus(DeviceIdentifier deviceIdentifier, Application application, + String s) throws ApplicationManagementException { + + } + + @Override + public String getApplicationStatus(DeviceIdentifier deviceIdentifier, + Application application) throws ApplicationManagementException { + return null; + } + + @Override public void installApplicationForDevices(Operation operation, List deviceIdentifiers) + throws ApplicationManagementException { + + } + + @Override public void installApplicationForUsers(Operation operation, List strings) + throws ApplicationManagementException { + + } + + @Override public void installApplicationForUserRoles(Operation operation, List strings) + throws ApplicationManagementException { + + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManager.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManager.java new file mode 100644 index 000000000..f3864fe4a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManager.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.*; +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 org.wso2.carbon.device.mgt.common.license.mgt.LicenseManager; +import org.wso2.carbon.device.mgt.extensions.license.mgt.registry.RegistryBasedLicenseManager; +import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; +import org.wso2.carbon.device.mgt.mobile.common.MobilePluginConstants; +import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dto.MobileDevice; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.WindowsDAOFactory; +import org.wso2.carbon.device.mgt.mobile.windows.impl.util.WindowsPluginUtils; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; +import org.wso2.carbon.registry.api.RegistryException; +import org.wso2.carbon.registry.api.Resource; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import java.io.StringReader; +import java.io.StringWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class WindowsDeviceManager implements DeviceManager { + + private AbstractMobileDeviceManagementDAOFactory daoFactory; + private LicenseManager licenseManager; + private FeatureManager featureManager = new WindowsFeatureManager(); + private static final Log log = LogFactory.getLog(WindowsDeviceManagementService.class); + + public WindowsDeviceManager() { + this.daoFactory = new WindowsDAOFactory(); + this.licenseManager = new RegistryBasedLicenseManager(); + + License defaultLicense = WindowsPluginUtils.getDefaultLicense(); + + try { + if (licenseManager.getLicense(WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS, + MobilePluginConstants.LANGUAGE_CODE_ENGLISH_US) == null) { + licenseManager.addLicense(WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS, defaultLicense); + } + featureManager.addSupportedFeaturesToDB(); + } catch (LicenseManagementException e) { + log.error("Error occurred while adding default license for Windows devices", e); + } catch (DeviceManagementException e) { + log.error("Error occurred while adding supported device features for Windows platform", e); + } + } + + @Override + public FeatureManager getFeatureManager() { + return featureManager; + } + + @Override + public boolean saveConfiguration(TenantConfiguration tenantConfiguration) + throws DeviceManagementException { + boolean status; + Resource resource; + try { + if (log.isDebugEnabled()) { + log.debug("Persisting windows configurations in Registry"); + } + String resourcePath = MobileDeviceManagementUtil.getPlatformConfigPath( + DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + StringWriter writer = new StringWriter(); + JAXBContext context = JAXBContext.newInstance(TenantConfiguration.class); + Marshaller marshaller = context.createMarshaller(); + marshaller.marshal(tenantConfiguration, writer); + + resource = MobileDeviceManagementUtil.getConfigurationRegistry().newResource(); + resource.setContent(writer.toString()); + resource.setMediaType(MobilePluginConstants.MEDIA_TYPE_XML); + MobileDeviceManagementUtil.putRegistryResource(resourcePath, resource); + status = true; + } catch (MobileDeviceMgtPluginException e) { + throw new DeviceManagementException( + "Error occurred while retrieving the Registry instance : " + e.getMessage(), e); + } catch (RegistryException e) { + throw new DeviceManagementException( + "Error occurred while persisting the Registry resource of Windows configuration : " + e.getMessage(), e); + } catch (JAXBException e) { + throw new DeviceManagementException( + "Error occurred while parsing the Windows configuration : " + e.getMessage(), e); + } + return status; + } + + @Override + public TenantConfiguration getConfiguration() throws DeviceManagementException { + Resource resource; + try { + String windowsTenantRegistryPath = + MobileDeviceManagementUtil.getPlatformConfigPath(DeviceManagementConstants. + MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + resource = MobileDeviceManagementUtil.getRegistryResource(windowsTenantRegistryPath); + if (resource != null) { + JAXBContext context = JAXBContext.newInstance(TenantConfiguration.class); + Unmarshaller unmarshaller = context.createUnmarshaller(); + return (TenantConfiguration) unmarshaller.unmarshal( + new StringReader(new String((byte[]) resource.getContent(), Charset. + forName(MobilePluginConstants.CHARSET_UTF8)))); + } + return null; + } catch (MobileDeviceMgtPluginException e) { + throw new DeviceManagementException( + "Error occurred while retrieving the Registry instance : " + e.getMessage(), e); + } catch (JAXBException e) { + throw new DeviceManagementException( + "Error occurred while parsing the Windows configuration : " + e.getMessage(), e); + } catch (RegistryException e) { + throw new DeviceManagementException( + "Error occurred while retrieving the Registry resource of Windows configuration : " + e.getMessage(), e); + } + } + + @Override + public boolean modifyEnrollment(Device device) throws DeviceManagementException { + boolean status; + MobileDevice mobileDevice = MobileDeviceManagementUtil.convertToMobileDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug("Modifying the Windows device enrollment data"); + } + WindowsDAOFactory.beginTransaction(); + status = daoFactory.getMobileDeviceDAO().updateMobileDevice(mobileDevice); + WindowsDAOFactory.commitTransaction(); + } catch (MobileDeviceManagementDAOException e) { + WindowsDAOFactory.rollbackTransaction(); + throw new DeviceManagementException("Error while updating the enrollment of the Windows device : " + + device.getDeviceIdentifier(), e); + } finally { + WindowsDAOFactory.closeConnection(); + } + return status; + } + + @Override + public boolean disenrollDevice(DeviceIdentifier deviceId) throws DeviceManagementException { + //Here we don't have anything specific to do. Hence returning. + return true; + } + + @Override + public boolean isEnrolled(DeviceIdentifier deviceId) throws DeviceManagementException { + boolean isEnrolled = false; + try { + if (log.isDebugEnabled()) { + log.debug("Checking the enrollment of Windows device : " + deviceId.getId()); + } + MobileDevice mobileDevice = + daoFactory.getMobileDeviceDAO().getMobileDevice(deviceId.getId()); + if (mobileDevice != null) { + isEnrolled = true; + } + } catch (MobileDeviceManagementDAOException e) { + String msg = "Error while checking the enrollment status of Windows device : " + + deviceId.getId(); + 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; + } + + public List getAllDevices() throws DeviceManagementException { + List devices = null; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Windows devices"); + } + WindowsDAOFactory.openConnection(); + List mobileDevices = daoFactory.getMobileDeviceDAO().getAllMobileDevices(); + if (mobileDevices != null) { + devices = new ArrayList<>(mobileDevices.size()); + for (MobileDevice mobileDevice : mobileDevices) { + devices.add(MobileDeviceManagementUtil.convertToDevice(mobileDevice)); + } + } + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException("Error occurred while fetching all Windows devices", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + return devices; + } + + @Override + public Device getDevice(DeviceIdentifier deviceId) throws DeviceManagementException { + Device device = null; + try { + if (log.isDebugEnabled()) { + log.debug("Getting the details of Windows device : '" + deviceId.getId() + "'"); + } + WindowsDAOFactory.openConnection(); + MobileDevice mobileDevice = daoFactory.getMobileDeviceDAO(). + getMobileDevice(deviceId.getId()); + device = MobileDeviceManagementUtil.convertToDevice(mobileDevice); + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException( + "Error occurred while fetching the Windows device: '" + deviceId.getId() + "'", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + return device; + } + + @Override + public boolean setOwnership(DeviceIdentifier deviceId, String ownershipType) + throws DeviceManagementException { + return true; + } + + @Override + public boolean isClaimable(DeviceIdentifier deviceIdentifier) throws DeviceManagementException { + return false; + } + + @Override + public boolean setStatus(DeviceIdentifier deviceIdentifier, String currentUser, + EnrolmentInfo.Status status) throws DeviceManagementException { + return false; + } + + @Override + public License getLicense(String languageCode) throws LicenseManagementException { + return licenseManager.getLicense(WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS, languageCode); + } + + @Override + public void addLicense(License license) throws LicenseManagementException { + licenseManager.addLicense(WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS, license); + } + + @Override + public boolean requireDeviceAuthorization() { + return false; + } + + @Override + public boolean updateDeviceInfo(DeviceIdentifier deviceIdentifier, + Device device) throws DeviceManagementException { + return true; + } + + @Override + public boolean enrollDevice(Device device) throws DeviceManagementException { + boolean status = false; + MobileDevice mobileDevice = MobileDeviceManagementUtil.convertToMobileDevice(device); + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new windows device : " + device.getDeviceIdentifier()); + } + boolean isEnrolled = this.isEnrolled( + new DeviceIdentifier(device.getDeviceIdentifier(), device.getType())); + if (isEnrolled) { + this.modifyEnrollment(device); + } else { + WindowsDAOFactory.beginTransaction(); + status = daoFactory.getMobileDeviceDAO().addMobileDevice(mobileDevice); + WindowsDAOFactory.commitTransaction(); + } + } catch (MobileDeviceManagementDAOException e) { + WindowsDAOFactory.rollbackTransaction(); + String msg = + "Error while enrolling the windows device : " + device.getDeviceIdentifier(); + throw new DeviceManagementException(msg, e); + } + return status; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsFeatureManager.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsFeatureManager.java new file mode 100644 index 000000000..6b501376a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsFeatureManager.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl; + +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.Feature; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; +import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.WindowsDAOFactory; +import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; + +import java.util.ArrayList; +import java.util.List; + +public class WindowsFeatureManager implements FeatureManager { + + private MobileFeatureDAO featureDAO; + + public WindowsFeatureManager() { + MobileDeviceManagementDAOFactory daoFactory = new WindowsDAOFactory(); + this.featureDAO = daoFactory.getMobileFeatureDAO(); + } + + @Override + public boolean addFeature(Feature feature) throws DeviceManagementException { + try { + WindowsDAOFactory.beginTransaction(); + MobileFeature mobileFeature = MobileDeviceManagementUtil.convertToMobileFeature(feature); + featureDAO.addFeature(mobileFeature); + WindowsDAOFactory.commitTransaction(); + return true; + } catch (MobileDeviceManagementDAOException e) { + WindowsDAOFactory.rollbackTransaction(); + throw new DeviceManagementException("Error occurred while adding the feature", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + } + + @Override + public boolean addFeatures(List features) throws DeviceManagementException { + List mobileFeatures = new ArrayList(features.size()); + for (Feature feature : features) { + mobileFeatures.add(MobileDeviceManagementUtil.convertToMobileFeature(feature)); + } + try { + WindowsDAOFactory.beginTransaction(); + featureDAO.addFeatures(mobileFeatures); + WindowsDAOFactory.commitTransaction(); + return true; + } catch (MobileDeviceManagementDAOException e) { + WindowsDAOFactory.rollbackTransaction(); + throw new DeviceManagementException("Error occurred while adding the features", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + } + + @Override + public Feature getFeature(String name) throws DeviceManagementException { + try { + WindowsDAOFactory.openConnection(); + MobileFeature mobileFeature = featureDAO.getFeatureByCode(name); + Feature feature = MobileDeviceManagementUtil.convertToFeature(mobileFeature); + return feature; + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException("Error occurred while retrieving the feature", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + } + + @Override + public List getFeatures() throws DeviceManagementException { + + try { + WindowsDAOFactory.openConnection(); + List mobileFeatures = featureDAO.getAllFeatures(); + List featureList = new ArrayList(mobileFeatures.size()); + for (MobileFeature mobileFeature : mobileFeatures) { + featureList.add(MobileDeviceManagementUtil.convertToFeature(mobileFeature)); + } + return featureList; + } catch (MobileDeviceManagementDAOException e) { + throw new DeviceManagementException("Error occurred while retrieving the list of features registered for " + + "Windows platform", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + } + + @Override + public boolean removeFeature(String code) throws DeviceManagementException { + boolean status; + try { + WindowsDAOFactory.beginTransaction(); + featureDAO.deleteFeatureByCode(code); + WindowsDAOFactory.commitTransaction(); + status = true; + } catch (MobileDeviceManagementDAOException e) { + WindowsDAOFactory.rollbackTransaction(); + throw new DeviceManagementException("Error occurred while removing the feature", e); + } finally { + WindowsDAOFactory.closeConnection(); + } + return status; + } + + @Override + public boolean addSupportedFeaturesToDB() throws DeviceManagementException { + synchronized (this) { + List supportedFeatures = getSupportedFeatures(); + List existingFeatures = this.getFeatures(); + List missingFeatures = MobileDeviceManagementUtil. + getMissingFeatures(supportedFeatures, existingFeatures); + if (missingFeatures.size() > 0) { + return this.addFeatures(missingFeatures); + } + return true; + } + } + + /** + * Get supported Windows features. + * + * @return Supported features. + */ + public static List getSupportedFeatures() { + List supportedFeatures = new ArrayList(); + Feature feature = new Feature(); + feature.setCode("DEVICE_LOCK"); + feature.setName("Device Lock"); + feature.setDescription("Lock the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("CAMERA"); + feature.setName("camera"); + feature.setDescription("Enable or disable camera"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_INFO"); + feature.setName("Device info"); + feature.setDescription("Request device information"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("WIPE_DATA"); + feature.setName("Wipe Data"); + feature.setDescription("Factory reset the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("ENCRYPT_STORAGE"); + feature.setName("Encrypt storage"); + feature.setDescription("Encrypt storage"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DEVICE_RING"); + feature.setName("Ring"); + feature.setDescription("Ring the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("PASSCODE_POLICY"); + feature.setName("Password Policy"); + feature.setDescription("Set passcode policy"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("DISENROLL"); + feature.setName("DisEnroll"); + feature.setDescription("DisEnroll the device"); + supportedFeatures.add(feature); + feature = new Feature(); + feature.setCode("LOCK_RESET"); + feature.setName("LockReset"); + feature.setDescription("Lock Reset device"); + supportedFeatures.add(feature); + return supportedFeatures; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsPolicyMonitoringService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsPolicyMonitoringService.java new file mode 100644 index 000000000..3c9c0f3ab --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsPolicyMonitoringService.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.policy.mgt.common.Policy; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceData; +import org.wso2.carbon.policy.mgt.common.monitor.ComplianceFeature; +import org.wso2.carbon.policy.mgt.common.monitor.PolicyComplianceException; +import org.wso2.carbon.policy.mgt.common.spi.PolicyMonitoringService; + +import java.util.ArrayList; +import java.util.List; + +public class WindowsPolicyMonitoringService implements PolicyMonitoringService { + + private static Log log = LogFactory.getLog(WindowsPolicyMonitoringService.class); + + @Override + public void notifyDevices(List list) throws PolicyComplianceException { + + } + + @Override + public ComplianceData checkPolicyCompliance(DeviceIdentifier deviceIdentifier, Policy policy, Object compliancePayload) + throws PolicyComplianceException { + if (log.isDebugEnabled()) { + log.debug("checking policy compliance status of device '" + deviceIdentifier.getId() + "'"); + } + List complianceFeatures = (List) compliancePayload; + List nonComplianceFeatures = new ArrayList<>(); + ComplianceData complianceData = new ComplianceData(); + + if (policy == null || compliancePayload == null) { + return complianceData; + } + + for (ComplianceFeature complianceFeature : complianceFeatures) { + if (!complianceFeature.isCompliant()) { + complianceData.setStatus(false); + nonComplianceFeatures.add(complianceFeature); + break; + } + } + complianceData.setComplianceFeatures(nonComplianceFeatures); + return complianceData; + } + + @Override + public String getType() { + return DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsDAOFactory.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsDAOFactory.java new file mode 100644 index 000000000..6e99fc6b9 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsDAOFactory.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceDAO; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.impl.WindowsDeviceDAOImpl; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.impl.WindowsFeatureDAOImpl; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class WindowsDAOFactory extends AbstractMobileDeviceManagementDAOFactory { + + private static final Log log = LogFactory.getLog(WindowsDAOFactory.class); + protected static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal<>(); + + public WindowsDAOFactory() { + this.dataSource = getDataSourceMap().get(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + } + + @Override + public MobileDeviceDAO getMobileDeviceDAO() { + return new WindowsDeviceDAOImpl(); + } + + @Override + public MobileFeatureDAO getMobileFeatureDAO() { + return new WindowsFeatureDAOImpl(); + } + + public static void beginTransaction() throws MobileDeviceManagementDAOException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while retrieving datasource connection", e); + } + } + + public static void openConnection() throws MobileDeviceManagementDAOException { + if (currentConnection.get() == null) { + Connection conn; + try { + conn = dataSource.getConnection(); + currentConnection.set(conn); + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException + ("Error occurred while retrieving data source connection", e); + } + } + } + + public static Connection getConnection() throws MobileDeviceManagementDAOException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException + ("Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() { + 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) { + log.error("Error occurred while committing the transaction", e); + } + } + + public static void closeConnection() { + Connection con = currentConnection.get(); + try { + con.close(); + } catch (SQLException e) { + log.error("Error occurred while close the connection"); + } + currentConnection.remove(); + } + + public static void rollbackTransaction() { + 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) { + log.warn("Error occurred while roll-backing the transaction", e); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsFeatureManagementDAOException.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsFeatureManagementDAOException.java new file mode 100644 index 000000000..1dd62d287 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/WindowsFeatureManagementDAOException.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.dao; + +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; + +/** + * Implement Exception class for Windows Device Features. + */ +public class WindowsFeatureManagementDAOException extends MobileDeviceManagementDAOException { + + private String message; + private static final long serialVersionUID = 2021891706072918865L; + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message and + * nested exception. + * + * @param message error message + * @param nestedException exception + */ + public WindowsFeatureManagementDAOException(String message, Exception nestedException) { + super(message, nestedException); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message + * and cause. + * + * @param message the detail message. + * @param cause the cause of this exception. + */ + public WindowsFeatureManagementDAOException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified detail message. + * + * @param message the detail message. + */ + public WindowsFeatureManagementDAOException(String message) { + super(message); + setErrorMessage(message); + } + + /** + * Constructs a new MobileDeviceManagementDAOException with the specified and cause. + * + * @param cause the cause of this exception. + */ + public WindowsFeatureManagementDAOException(Throwable cause) { + super(cause); + } + + public String getMessage() { + return message; + } + + public void setErrorMessage(String errorMessage) { + this.message = errorMessage; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsDeviceDAOImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsDeviceDAOImpl.java new file mode 100644 index 000000000..f65d42fc7 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsDeviceDAOImpl.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceDAO; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.mobile.dto.MobileDevice; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.WindowsDAOFactory; +import org.wso2.carbon.device.mgt.mobile.windows.impl.util.WindowsPluginConstants; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implements MobileDeviceDAO for Windows Devices. + */ +public class WindowsDeviceDAOImpl implements MobileDeviceDAO { + + private static final Log log = LogFactory.getLog(WindowsDeviceDAOImpl.class); + + @Override + public MobileDevice getMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + MobileDevice mobileDevice = null; + try { + conn = WindowsDAOFactory.getConnection(); + String selectDBQuery = + "SELECT DEVICE_ID, CHANNEL_URI, DEVICE_INFO, IMEI, IMSI, " + + "OS_VERSION, DEVICE_MODEL, VENDOR, LATITUDE, LONGITUDE, SERIAL, MAC_ADDRESS," + + " OS_VERSION, DEVICE_NAME " + + "FROM WIN_DEVICE WHERE DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, mblDeviceId); + rs = stmt.executeQuery(); + + while (rs.next()) { + mobileDevice = new MobileDevice(); + mobileDevice.setMobileDeviceId(rs.getString(WindowsPluginConstants.DEVICE_ID)); + mobileDevice.setImei(rs.getString(WindowsPluginConstants.IMEI)); + mobileDevice.setImsi(rs.getString(WindowsPluginConstants.IMSI)); + mobileDevice.setModel(rs.getString(WindowsPluginConstants.DEVICE_MODEL)); + mobileDevice.setVendor(rs.getString(WindowsPluginConstants.VENDOR)); + mobileDevice.setLatitude(rs.getString(WindowsPluginConstants.LATITUDE)); + mobileDevice.setLongitude(rs.getString(WindowsPluginConstants.LONGITUDE)); + mobileDevice.setSerial(rs.getString(WindowsPluginConstants.SERIAL)); + mobileDevice.setOsVersion(rs.getString(WindowsPluginConstants.LATITUDE)); + + Map propertyMap = new HashMap<>(); + propertyMap.put(WindowsPluginConstants.CHANNEL_URI, rs.getString(WindowsPluginConstants.CHANNEL_URI)); + propertyMap.put(WindowsPluginConstants.DEVICE_INFO, rs.getString(WindowsPluginConstants.DEVICE_INFO)); + propertyMap.put(WindowsPluginConstants.MAC_ADDRESS, rs.getString(WindowsPluginConstants.MAC_ADDRESS)); + propertyMap.put(WindowsPluginConstants.DEVICE_NAME, rs.getString(WindowsPluginConstants.DEVICE_NAME)); + + mobileDevice.setDeviceProperties(propertyMap); + } + if (log.isDebugEnabled()) { + log.debug("All Windows device details have fetched from Windows database."); + } + return mobileDevice; + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while fetching all Windows device data", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + } + + @Override + public boolean addMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = WindowsDAOFactory.getConnection(); + String createDBQuery = + "INSERT INTO WIN_DEVICE(DEVICE_ID, CHANNEL_URI, DEVICE_INFO, IMEI, " + + "IMSI, OS_VERSION, DEVICE_MODEL, VENDOR, LATITUDE, LONGITUDE, SERIAL, " + + "MAC_ADDRESS, DEVICE_NAME) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, mobileDevice.getMobileDeviceId()); + + Map properties = mobileDevice.getDeviceProperties(); + stmt.setString(2, properties.get(WindowsPluginConstants.CHANNEL_URI)); + stmt.setString(3, properties.get(WindowsPluginConstants.DEVICE_INFO)); + stmt.setString(4, mobileDevice.getImei()); + stmt.setString(5, mobileDevice.getImsi()); + stmt.setString(6, mobileDevice.getOsVersion()); + stmt.setString(7, mobileDevice.getModel()); + stmt.setString(8, mobileDevice.getVendor()); + stmt.setString(9, mobileDevice.getLatitude()); + stmt.setString(10, mobileDevice.getLongitude()); + stmt.setString(11, mobileDevice.getSerial()); + stmt.setString(12, properties.get(WindowsPluginConstants.MAC_ADDRESS)); + stmt.setString(13, properties.get(WindowsPluginConstants.DEVICE_NAME)); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Windows device " + mobileDevice.getMobileDeviceId() + " data has been" + + " added to the Windows database."); + } + } + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while adding the Windows device '" + + mobileDevice.getMobileDeviceId() + "' to the Windows db.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean updateMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = WindowsDAOFactory.getConnection(); + String updateDBQuery = + "UPDATE WIN_DEVICE SET CHANNEL_URI = ?, DEVICE_INFO = ?, IMEI = ?, IMSI = ?, " + + "OS_VERSION = ?, DEVICE_MODEL = ?, VENDOR = ?, LATITUDE = ?, LONGITUDE = ?, " + + "SERIAL = ?, MAC_ADDRESS = ?, DEVICE_NAME = ? WHERE DEVICE_ID = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + + Map properties = mobileDevice.getDeviceProperties(); + stmt.setString(1, properties.get(WindowsPluginConstants.CHANNEL_URI)); + stmt.setString(2, properties.get(WindowsPluginConstants.DEVICE_INFO)); + stmt.setString(3, mobileDevice.getImei()); + stmt.setString(4, mobileDevice.getImsi()); + stmt.setString(5, mobileDevice.getOsVersion()); + stmt.setString(6, mobileDevice.getModel()); + stmt.setString(7, mobileDevice.getVendor()); + stmt.setString(8, mobileDevice.getLatitude()); + stmt.setString(9, mobileDevice.getLongitude()); + stmt.setString(10, mobileDevice.getSerial()); + stmt.setString(11, properties.get(WindowsPluginConstants.MAC_ADDRESS)); + stmt.setString(12, properties.get(WindowsPluginConstants.DEVICE_NAME)); + stmt.setString(13, mobileDevice.getMobileDeviceId()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Windows device " + mobileDevice.getMobileDeviceId() + " data has been" + + " modified."); + } + } + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while modifying the Windows device '" + + mobileDevice.getMobileDeviceId() + "' data.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = WindowsDAOFactory.getConnection(); + String deleteDBQuery = "DELETE FROM WIN_DEVICE WHERE DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, mblDeviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Windows device " + mblDeviceId + " data has deleted" + + " from the windows database."); + } + } + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while deleting windows device '" + + mblDeviceId + "'", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public List getAllMobileDevices() throws MobileDeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + MobileDevice mobileDevice; + List mobileDevices = new ArrayList<>(); + try { + conn = WindowsDAOFactory.getConnection(); + String selectDBQuery = + "SELECT DEVICE_ID, CHANNEL_URI, DEVICE_INFO, IMEI, IMSI, " + + "OS_VERSION, DEVICE_MODEL, VENDOR, LATITUDE, LONGITUDE, SERIAL, MAC_ADDRESS," + + " OS_VERSION, DEVICE_NAME " + + "FROM WIN_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + rs = stmt.executeQuery(); + + while (rs.next()) { + mobileDevice = new MobileDevice(); + mobileDevice.setMobileDeviceId(rs.getString(WindowsPluginConstants.DEVICE_ID)); + mobileDevice.setVendor(rs.getString(WindowsPluginConstants.IMEI)); + mobileDevice.setLatitude(rs.getString(WindowsPluginConstants.IMSI)); + mobileDevice.setLongitude(rs.getString(WindowsPluginConstants.OS_VERSION)); + mobileDevice.setImei(rs.getString(WindowsPluginConstants.DEVICE_MODEL)); + mobileDevice.setImsi(rs.getString(WindowsPluginConstants.VENDOR)); + mobileDevice.setOsVersion(rs.getString(WindowsPluginConstants.LATITUDE)); + + Map propertyMap = new HashMap<>(); + propertyMap.put(WindowsPluginConstants.CHANNEL_URI, rs.getString(WindowsPluginConstants.CHANNEL_URI)); + propertyMap.put(WindowsPluginConstants.DEVICE_INFO, rs.getString(WindowsPluginConstants.DEVICE_INFO)); + propertyMap.put(WindowsPluginConstants.DEVICE_NAME, rs.getString(WindowsPluginConstants.DEVICE_NAME)); + mobileDevice.setDeviceProperties(propertyMap); + mobileDevices.add(mobileDevice); + } + if (log.isDebugEnabled()) { + log.debug("All Windows device details have fetched from Windows database."); + } + return mobileDevices; + } catch (SQLException e) { + throw new MobileDeviceManagementDAOException("Error occurred while fetching all Windows device data", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsFeatureDAOImpl.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsFeatureDAOImpl.java new file mode 100644 index 000000000..a1e42cdff --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/dao/impl/WindowsFeatureDAOImpl.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; +import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.WindowsDAOFactory; +import org.wso2.carbon.device.mgt.mobile.windows.impl.dao.WindowsFeatureManagementDAOException; +import org.wso2.carbon.device.mgt.mobile.windows.impl.util.WindowsPluginConstants; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Implement MobileFeatureDAO for Windows devices. + */ +public class WindowsFeatureDAOImpl implements MobileFeatureDAO { + + private static final Log log = LogFactory.getLog(WindowsFeatureDAOImpl.class); + + public WindowsFeatureDAOImpl() { + + } + + @Override + public boolean addFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + boolean status; + Connection conn; + try { + conn = WindowsDAOFactory.getConnection(); + String sql = "INSERT INTO WIN_FEATURE(CODE, NAME, DESCRIPTION) VALUES (?, ?, ?)"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, mobileFeature.getCode()); + stmt.setString(2, mobileFeature.getName()); + stmt.setString(3, mobileFeature.getDescription()); + stmt.executeUpdate(); + status = true; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException( + "Error occurred while adding windows feature '" + + mobileFeature.getName() + "' into the metadata repository", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean addFeatures(List mobileFeatures) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + boolean status = false; + Connection conn; + try { + conn = WindowsDAOFactory.getConnection(); + stmt = conn.prepareStatement("INSERT INTO WIN_FEATURE(CODE, NAME, DESCRIPTION) VALUES (?, ?, ?)"); + for (MobileFeature mobileFeature : mobileFeatures) { + stmt.setString(1, mobileFeature.getCode()); + stmt.setString(2, mobileFeature.getName()); + stmt.setString(3, mobileFeature.getDescription()); + stmt.addBatch(); + } + stmt.executeBatch(); + status = true; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException( + "Error occurred while adding windows features into the metadata repository", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean updateFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = WindowsDAOFactory.getConnection(); + String updateDBQuery = + "UPDATE WIN_FEATURE SET NAME = ?, DESCRIPTION = ?" + + "WHERE CODE = ?"; + stmt = conn.prepareStatement(updateDBQuery); + stmt.setString(1, mobileFeature.getName()); + stmt.setString(2, mobileFeature.getDescription()); + stmt.setString(3, mobileFeature.getCode()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Windows Feature " + mobileFeature.getCode() + " data has been " + + "modified."); + } + } + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException("Error occurred while updating the Windows Feature '" + + mobileFeature.getCode() + "' to the Windows db.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + boolean status = false; + Connection conn; + try { + conn = WindowsDAOFactory.getConnection(); + String sql = "DELETE FROM WIN_FEATURE WHERE ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, mblFeatureId); + stmt.execute(); + status = true; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException( + "Error occurred while deleting windows feature '" + + mblFeatureId + "' from Windows database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public boolean deleteFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + boolean status = false; + Connection conn; + try { + conn = WindowsDAOFactory.getConnection(); + String sql = "DELETE FROM WIN_FEATURE WHERE CODE = ?"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, mblFeatureCode); + stmt.execute(); + status = true; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException( + "Error occurred while deleting windows feature '" + + mblFeatureCode + "' from Windows database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return status; + } + + @Override + public MobileFeature getFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn; + try { + conn = WindowsDAOFactory.getConnection(); + String sql = "SELECT ID, CODE, NAME, DESCRIPTION FROM WIN_FEATURE WHERE ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, mblFeatureId); + rs = stmt.executeQuery(); + MobileFeature mobileFeature = null; + if (rs.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(rs.getInt(WindowsPluginConstants.WINDOWS_FEATURE_ID)); + mobileFeature.setCode(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_CODE)); + mobileFeature.setName(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_NAME)); + mobileFeature.setDescription(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_DESCRIPTION)); + mobileFeature.setDeviceType( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + } + return mobileFeature; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException( + "Error occurred while retrieving windows feature '" + + mblFeatureId + "' from the Windows database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + } + + @Override + public MobileFeature getFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn; + try { + conn = WindowsDAOFactory.getConnection(); + String sql = "SELECT ID, CODE, NAME, DESCRIPTION FROM WIN_FEATURE WHERE CODE = ?"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, mblFeatureCode); + rs = stmt.executeQuery(); + MobileFeature mobileFeature = null; + if (rs.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(rs.getInt(WindowsPluginConstants.WINDOWS_FEATURE_ID)); + mobileFeature.setCode(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_CODE)); + mobileFeature.setName(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_NAME)); + mobileFeature.setDescription(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_DESCRIPTION)); + mobileFeature.setDeviceType( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + } + return mobileFeature; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException( + "Error occurred while retrieving windows feature '" + + mblFeatureCode + "' from the Windows database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + } + + @Override + public List getFeatureByDeviceType(String deviceType) throws MobileDeviceManagementDAOException { + return this.getAllFeatures(); + } + + @Override + public List getAllFeatures() throws MobileDeviceManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn; + List features = new ArrayList<>(); + try { + conn = WindowsDAOFactory.getConnection(); + String sql = "SELECT ID, CODE, NAME, DESCRIPTION FROM WIN_FEATURE"; + stmt = conn.prepareStatement(sql); + rs = stmt.executeQuery(); + MobileFeature mobileFeature; + while (rs.next()) { + mobileFeature = new MobileFeature(); + mobileFeature.setId(rs.getInt(WindowsPluginConstants.WINDOWS_FEATURE_ID)); + mobileFeature.setCode(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_CODE)); + mobileFeature.setName(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_NAME)); + mobileFeature.setDescription(rs.getString(WindowsPluginConstants.WINDOWS_FEATURE_DESCRIPTION)); + mobileFeature.setDeviceType( + DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS); + features.add(mobileFeature); + } + return features; + } catch (SQLException e) { + throw new WindowsFeatureManagementDAOException("Error occurred while retrieving all " + + "windows features from the Windows database.", e); + } finally { + MobileDeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginConstants.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginConstants.java new file mode 100644 index 000000000..7596871c9 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginConstants.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.util; + +/** + * Define constance used by Windows plugin. + */ +public class WindowsPluginConstants { + + //properties related to database table WINDOWS_DEVICE + public static final String DEVICE_ID = "DEVICE_ID"; + public static final String CHANNEL_URI = "CHANNEL_URI"; + public static final String DEVICE_INFO = "DEVICE_INFO"; + public static final String IMEI = "IMEI"; + public static final String IMSI = "IMSI"; + public static final String OS_VERSION = "OS_VERSION"; + public static final String DEVICE_MODEL = "DEVICE_MODEL"; + public static final String VENDOR = "VENDOR"; + public static final String LATITUDE = "LATITUDE"; + public static final String LONGITUDE = "LONGITUDE"; + public static final String SERIAL = "SERIAL"; + public static final String MAC_ADDRESS = "MAC_ADDRESS"; + public static final String DEVICE_NAME = "DEVICE_NAME"; + + //Properties related to WIN_FEATURE table + public static final String WINDOWS_FEATURE_ID = "ID"; + public static final String WINDOWS_FEATURE_CODE = "CODE"; + public static final String WINDOWS_FEATURE_NAME = "NAME"; + public static final String WINDOWS_FEATURE_DESCRIPTION = "DESCRIPTION"; + + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginUtils.java new file mode 100644 index 000000000..2c18646ce --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsPluginUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.util; + +import org.wso2.carbon.device.mgt.common.license.mgt.License; +import org.wso2.carbon.device.mgt.mobile.windows.impl.WindowsDeviceManagementService; + +/** + * Contains utility method used by Windows plugin. + */ +public class WindowsPluginUtils { + + public static License getDefaultLicense() { + License license = new License(); + license.setName(WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS); + license.setLanguage("en_US"); + license.setVersion("1.0.0"); + license.setText("This End User License Agreement (\"Agreement\") is a legal agreement between you (\"You\") " + + "and WSO2, Inc., regarding the enrollment of Your personal mobile device (\"Device\") in SoR's " + + "mobile device management program, and the loading to and removal from Your Device and Your use " + + "of certain applications and any associated software and user documentation, whether provided in " + + "\"online\" or electronic format, used in connection with the operation of or provision of services " + + "to WSO2, Inc., BY SELECTING \"I ACCEPT\" DURING INSTALLATION, YOU ARE ENROLLING YOUR DEVICE, AND " + + "THEREBY AUTHORIZING SOR OR ITS AGENTS TO INSTALL, UPDATE AND REMOVE THE APPS FROM YOUR DEVICE AS " + + "DESCRIBED IN THIS AGREEMENT. YOU ARE ALSO EXPLICITLY ACKNOWLEDGING AND AGREEING THAT (1) THIS IS " + + "A BINDING CONTRACT AND (2) YOU HAVE READ AND AGREE TO THE TERMS OF THIS AGREEMENT.\n" + + "\n" + + "IF YOU DO NOT ACCEPT THESE TERMS, DO NOT ENROLL YOUR DEVICE AND DO NOT PROCEED ANY FURTHER.\n" + + "\n" + + "You agree that: (1) You understand and agree to be bound by the terms and conditions contained " + + "in this Agreement, and (2) You are at least 21 years old and have the legal capacity to enter " + + "into this Agreement as defined by the laws of Your jurisdiction. SoR shall have the right, " + + "without prior notice, to terminate or suspend (i) this Agreement, (ii) the enrollment of Your " + + "Device, or (iii) the functioning of the Apps in the event of a violation of this Agreement or " + + "the cessation of Your relationship with SoR (including termination of Your employment if You are " + + "an employee or expiration or termination of Your applicable franchise or supply agreement if You " + + "are a franchisee of or supplier to the WSO2 WSO2, Inc., system). SoR expressly reserves all " + + "rights not expressly granted herein."); + return license; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsUtils.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsUtils.java new file mode 100644 index 000000000..7fba2f5ca --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/util/WindowsUtils.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.impl.util; + +import java.util.Map; + +/** + * Contains utility methods used by Windows plugin. + */ +public class WindowsUtils { + public static String getDeviceProperty(Map deviceProperties, String property) { + + String deviceProperty = deviceProperties.get(property); + if (deviceProperty == null) { + return null; + } + return deviceProperty; + } +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementDataHolder.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementDataHolder.java new file mode 100644 index 000000000..600aecc1c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementDataHolder.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.internal; + +import org.wso2.carbon.registry.core.service.RegistryService; + +/** + * DataHolder class of Mobile plugins component. + */ +public class WindowsDeviceManagementDataHolder { + + private RegistryService registryService; + + private static WindowsDeviceManagementDataHolder thisInstance = new WindowsDeviceManagementDataHolder(); + + private WindowsDeviceManagementDataHolder() { + } + + public static WindowsDeviceManagementDataHolder getInstance() { + return thisInstance; + } + + public RegistryService getRegistryService() { + return registryService; + } + + public void setRegistryService(RegistryService registryService) { + this.registryService = registryService; + } + +} diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementServiceComponent.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementServiceComponent.java new file mode 100644 index 000000000..5fd45c61a --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/internal/WindowsDeviceManagementServiceComponent.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.windows.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; +import org.wso2.carbon.device.mgt.mobile.windows.impl.WindowsDeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.windows.impl.WindowsPolicyMonitoringService; +import org.wso2.carbon.ndatasource.core.DataSourceService; +import org.wso2.carbon.policy.mgt.common.spi.PolicyMonitoringService; +import org.wso2.carbon.registry.core.service.RegistryService; + +/** + * @scr.component name="org.wso2.carbon.device.mgt.mobile.windows.impl.internal.WindowsDeviceManagementServiceComponent" + * immediate="true" + * @scr.reference name="org.wso2.carbon.ndatasource" + * interface="org.wso2.carbon.ndatasource.core.DataSourceService" + * cardinality="1..1" + * policy="dynamic" + * bind="setDataSourceService" + * unbind="unsetDataSourceService" + * @scr.reference name="registry.service" + * interface="org.wso2.carbon.registry.core.service.RegistryService" cardinality="0..1" + * policy="dynamic" bind="setRegistryService" unbind="unsetRegistryService" + *

      + * Adding reference to API Manager Configuration service is an unavoidable hack to get rid of NPEs thrown while + * initializing APIMgtDAOs attempting to register APIs programmatically. APIMgtDAO needs to be proper cleaned up + * to avoid as an ideal fix + */ +public class WindowsDeviceManagementServiceComponent { + + private ServiceRegistration androidServiceRegRef; + + private static final Log log = LogFactory.getLog(WindowsDeviceManagementServiceComponent.class); + + protected void activate(ComponentContext ctx) { + + if (log.isDebugEnabled()) { + log.debug("Activating Android Mobile Device Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + + androidServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + new WindowsDeviceManagementService(), null); + + // Policy management service + + bundleContext.registerService(PolicyMonitoringService.class, + new WindowsPolicyMonitoringService(), null); + + if (log.isDebugEnabled()) { + log.debug("Android Mobile Device Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Android Mobile Device Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating Android Mobile Device Management Service Component"); + } + try { + if (androidServiceRegRef != null) { + androidServiceRegRef.unregister(); + } + if (log.isDebugEnabled()) { + log.debug( + "Android Mobile Device Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Android Mobile Device Management bundle", e); + } + } + + protected void setDataSourceService(DataSourceService dataSourceService) { + /* This is to avoid mobile device management component getting initialized before the underlying datasources + are registered */ + if (log.isDebugEnabled()) { + log.debug("Data source service set to android mobile service component"); + } + } + + protected void unsetDataSourceService(DataSourceService dataSourceService) { + //do nothing + } + + protected void setRegistryService(RegistryService registryService) { + if (log.isDebugEnabled()) { + log.debug("RegistryService acquired"); + } + WindowsDeviceManagementDataHolder.getInstance().setRegistryService(registryService); + } + + protected void unsetRegistryService(RegistryService registryService) { + WindowsDeviceManagementDataHolder.getInstance().setRegistryService(null); + } + +} diff --git a/components/mobile-plugins/windows-plugin/pom.xml b/components/mobile-plugins/windows-plugin/pom.xml new file mode 100644 index 000000000..e5de76e61 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/pom.xml @@ -0,0 +1,61 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + mobile-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.devicemgt-plugins + windows-plugin + pom + WSO2 Carbon - Mobile Plugins + http://wso2.org + + + org.wso2.carbon.device.mgt.mobile.windows + org.wso2.carbon.device.mgt.mobile.windows.agent + + + + + + + org.apache.felix + maven-scr-plugin + 1.7.2 + + + generate-scr-scrdescriptor + + scr + + + + + + + + + diff --git a/pom.xml b/pom.xml index f1e904679..0848df962 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,8 @@ --> - + 4.0.0 org.wso2.carbon.devicemgt-plugins @@ -37,6 +38,8 @@ components/device-mgt + + features/device-mgt @@ -245,6 +248,250 @@ zip ${carbon.device.mgt.version} + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + ${carbon.device.mgt.version} + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + ${carbon.device.mgt.version} + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.dynamic.client.registration + ${carbon.device.mgt.version} + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.jwt.client.extension + ${carbon.devicemgt.version} + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.application.extension + ${carbon.devicemgt.version} + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + ${carbon.devicemgt.version} + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + ${carbon.devicemgt.version} + + + + org.wso2.carbon.commons + org.wso2.carbon.databridge.commons + ${carbon.commons.version} + + + org.wso2.carbon.analytics-common + org.wso2.carbon.databridge.core + ${carbon.analytics.common.version} + + + org.wso2.carbon.analytics-common + org.wso2.carbon.databridge.agent + ${carbon.analytics.common.version} + + + commons-codec + commons-codec + + + + + org.wso2.carbon.analytics-common + org.wso2.carbon.databridge.commons + ${carbon.analytics.common.version} + + + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + ${carbon.devicemgt.plugins.version} + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.api + ${carbon.devicemgt.plugins.version} + war + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.androidsense.plugin + ${carbon.devicemgt.plugins.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.androidsense.controller.api + ${carbon.devicemgt.plugins.version} + war + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.androidsense.manager.api + ${carbon.devicemgt.plugins.version} + war + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.arduino.plugin.impl + ${carbon.devicemgt.plugins.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.arduino.service.impl + ${carbon.devicemgt.plugins.version} + war + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.arduino.manager.service.impl + ${carbon.devicemgt.plugins.version} + war + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.arduino.controller.service.impl + ${carbon.devicemgt.plugins.version} + war + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.digitaldisplay.plugin + ${carbon.devicemgt.plugins.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.digitaldisplay.manager.api + ${carbon.devicemgt.plugins.version} + war + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.digitaldisplay.controller.api + ${carbon.devicemgt.plugins.version} + war + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.droneanalyzer.plugin + ${carbon.devicemgt.plugins.version} + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.droneanalyzer.manager.api + ${carbon.devicemgt.plugins.version} + war + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.droneanalyzer.controller.api + ${carbon.devicemgt.plugins.version} + war + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.raspberrypi.plugin.impl + ${carbon.devicemgt.plugins.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.raspberrypi.manager.service.impl + ${carbon.devicemgt.plugins.version} + war + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.raspberrypi.controller.service.impl + ${carbon.devicemgt.plugins.version} + war + + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.plugin.impl + ${carbon.devicemgt.plugins.version} + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.manager.service.impl + ${carbon.devicemgt.plugins.version} + war + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.controller.service.impl + ${carbon.devicemgt.plugins.version} + war + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.impl + ${carbon.devicemgt.plugins.version} + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.virtualfirealarm.agent.advanced.impl + ${carbon.devicemgt.plugins.version} + + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.camera.plugin.impl + ${carbon.devicemgt.plugins.version} + + + + + + org.wso2.carbon.analytics + org.wso2.carbon.analytics.datasource.commons + ${carbon.analytics.version} + @@ -257,6 +504,16 @@ org.wso2.carbon.device.mgt.mobile.url.printer ${carbon.mobile.device.mgt.version} + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile + ${carbon.mobile.device.mgt.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.android + ${carbon.mobile.device.mgt.version} + @@ -305,6 +562,11 @@ jdbc-pool ${orbit.tomcat.jdbc.pooling.version} + + org.wso2.tomcat + tomcat-servlet-api + ${orbit.version.tomcat-servlet-api} + + + org.igniterealtime.smack.wso2 + smack + ${smack.wso2.version} + + + org.igniterealtime.smack.wso2 + smackx + ${smackx.wso2.version} + + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + ${cxf.version} + + + org.apache.cxf + cxf-rt-frontend-jaxrs + ${cxf.version} + + + org.apache.cxf + cxf-rt-transports-http + ${cxf.version} + + + javax.ws.rs + jsr311-api + ${javax.ws.rs.version} + + + + + commons-httpclient.wso2 + commons-httpclient + ${orbit.version.commons-httpclient} + + + commons-codec.wso2 + commons-codec + ${commons-codec.wso2.version} + + + org.codehaus.jackson + jackson-core-asl + ${jackson.version} + + + org.codehaus.jackson + jackson-jaxrs + ${jackson.version} + + + + + org.apache.cxf + cxf-rt-bindings-soap + ${cxf.version} + + + org.apache.cxf + cxf-rt-bindings-http + ${cxf.bindings.version} + + + org.apache.ws.security + wss4j + ${wss4j.security.version} + + + org.apache.cxf + cxf-rt-rs-extension-providers + ${cxf.version} + + + org.apache.cxf + cxf-rt-ws-security + ${cxf.version} + + + org.apache.wss4j + wss4j-ws-security-common + ${wss4j.security.common.version} + + + org.apache.ws.commons.axiom + axiom-api + ${axiom-api.version} + + + org.apache.ws.commons.axiom + axiom-impl + ${axiom-api.version} + + + log4j + log4j + ${log4j.version} + + + org.springframework + spring-web + ${spring-web.version} + + + org.springframework.ws + spring-ws-security + ${spring-ws-security.version} + + + org.springframework + spring-context + ${spring-web.version} + + + com.sun.xml.ws + jaxws-rt + ${jaxws-rt.version} + + + com.sun.xml.messaging.saaj + saaj-impl + ${saaj-impl.version} + + + org.bouncycastle + bcpkix-jdk15on + ${bcpkix-jdk15on.version} + + + org.bouncycastle + bcprov-jdk15on + ${bcpkix-jdk15on.version} + + + org.codehaus.plexus + plexus-utils + ${plexus-utils.version} + + + com.madgag.spongycastle + pkix + ${spongycastle.version} + + + com.madgag.spongycastle + prov + ${spongycastle.version} + + + com.madgag.spongycastle + core + ${spongycastle.version} + + + joda-time + joda-time + ${joda-time.version} + + + + commons-io + commons-io + ${commons-io.version} + + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth.stub + ${carbon.identity.version} + provided + + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth + ${carbon.identity.version} + provided + + + + commons-collections + commons-collections + ${commons-collections.version} + + + commons-configuration + commons-configuration + ${commons-configuration.version} + + + + org.wso2.carbon.commons + org.wso2.carbon.user.mgt + ${carbon.commons.version} + + + + junit + junit + test + ${junit.version} + + @@ -552,6 +1045,7 @@ 1.3 + 4.8.2 4.3.1 6.8 @@ -566,34 +1060,58 @@ 2.7.16 + 2.5.11 1.9.0 1.1.1 + + 1.1.0-SNAPSHOT + + + 2.1.0-SNAPSHOT + 4.4.8 4.6.0 - + 5.0.7 - + 4.5.0 - + 4.4.8 - + 4.5.8 - + 1.1.0-SNAPSHOT [0.8.0, 2.0.0) + + 5.0.3 + 2.1.0-SNAPSHOT + + 3.0.4.wso2v1 + 3.0.4.wso2v1 + 1.0.2 + + + 8.1.3.v20120416 + + + 5.0.11-SNAPSHOT + [5.0.11,6.0.0) + 1.0.6-SNAPSHOT + [1.0.6,2.0.0] + 1.51.0.0 1.49 @@ -602,8 +1120,33 @@ 2.2.4 1.0.2 - - github-scm + 3.1.0.wso2v2 + 1.4.0.wso2v1 + + 6.0 + + 1.2.14 + 1.2.17 + 3.0.5.RELEASE + 2.1.0.RELEASE + 2.2.8 + 1.3.18 + 1.49 + 3.0.21 + 2.2 + 1.6.17 + 2.0.0 + + 2.4 + 3.0.0.wso2v1 + 3.2.2 + 1.8 + + 7.0.59.wso2v1 + + + + github-scm @@ -715,6 +1258,11 @@ build-helper-maven-plugin 1.8 + + org.apache.maven.plugins + maven-war-plugin + 2.2 + @@ -798,5 +1346,5 @@ GCM Server repository - GitHub https://github.com/slorber/gcm-server-repository/raw/master/releases/ - + From cb9ab9fb0a77babb4d2e87a8306b1f4e2288c8f7 Mon Sep 17 00:00:00 2001 From: mharindu Date: Tue, 29 Mar 2016 11:10:50 +0530 Subject: [PATCH 04/10] Added unlock feature --- .../impl/android/AndroidFeatureManager.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java index 6b29e8486..3cbabce0e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java @@ -145,101 +145,127 @@ public class AndroidFeatureManager implements FeatureManager { //Get the supported feature list. private static List getSupportedFeatures() { List supportedFeatures = new ArrayList(); + Feature feature = new Feature(); feature.setCode("DEVICE_LOCK"); feature.setName("Device Lock"); feature.setDescription("Lock the device"); supportedFeatures.add(feature); + + feature = new Feature(); + feature.setCode("DEVICE_UNLOCK"); + feature.setName("Device Unlock"); + feature.setDescription("Unlock the device"); + supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("DEVICE_LOCATION"); feature.setName("Location"); feature.setDescription("Request coordinates of device location"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("WIFI"); feature.setName("wifi"); feature.setDescription("Setting up wifi configuration"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("CAMERA"); feature.setName("camera"); feature.setDescription("Enable or disable camera"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("EMAIL"); feature.setName("Email"); feature.setDescription("Configure email settings"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("DEVICE_MUTE"); - feature.setName("mute"); + feature.setName("Mute"); feature.setDescription("Enable mute in the device"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("DEVICE_INFO"); feature.setName("Device info"); feature.setDescription("Request device information"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("ENTERPRISE_WIPE"); feature.setName("Enterprise Wipe"); feature.setDescription("Remove enterprise applications"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("CLEAR_PASSWORD"); feature.setName("Clear Password"); feature.setDescription("Clear current password"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("WIPE_DATA"); feature.setName("Wipe Data"); feature.setDescription("Factory reset the device"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("APPLICATION_LIST"); feature.setName("Application List"); feature.setDescription("Request list of current installed applications"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("CHANGE_LOCK_CODE"); feature.setName("Change Lock-code"); feature.setDescription("Change current lock code"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("INSTALL_APPLICATION"); feature.setName("Install App"); feature.setDescription("Install Enterprise or Market application"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("UNINSTALL_APPLICATION"); feature.setName("Uninstall App"); feature.setDescription("Uninstall application"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("BLACKLIST_APPLICATIONS"); feature.setName("Blacklist app"); feature.setDescription("Blacklist applications"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("ENCRYPT_STORAGE"); feature.setName("Encrypt storage"); feature.setDescription("Encrypt storage"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("DEVICE_RING"); feature.setName("Ring"); feature.setDescription("Ring the device"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("PASSCODE_POLICY"); feature.setName("Password Policy"); feature.setDescription("Set passcode policy"); supportedFeatures.add(feature); + feature = new Feature(); feature.setCode("NOTIFICATION"); feature.setName("Message"); feature.setDescription("Send message"); supportedFeatures.add(feature); + return supportedFeatures; } } \ No newline at end of file From f6d04fba4b42de04f8e82f2d9441660fd4ab2746 Mon Sep 17 00:00:00 2001 From: charithag Date: Tue, 29 Mar 2016 12:59:10 +0530 Subject: [PATCH 05/10] Fix module locations --- .../pom.xml | 173 --------- .../AbstractMobileOperationManager.java | 41 --- .../device/mgt/mobile/DataSourceListener.java | 25 -- .../DataSourceNotAvailableException.java | 52 --- .../MobileDeviceMgtPluginException.java | 57 --- .../mobile/common/MobilePluginConstants.java | 29 -- .../MobileDeviceConfigurationManager.java | 79 ---- .../config/MobileDeviceManagementConfig.java | 42 --- .../MobileDeviceManagementRepository.java | 57 --- .../datasource/DataSourceConfigAdapter.java | 51 --- .../datasource/JNDILookupDefinition.java | 79 ---- .../datasource/MobileDataSourceConfig.java | 51 --- .../MobileDataSourceConfigurations.java | 41 --- ...tractMobileDeviceManagementDAOFactory.java | 102 ------ .../mgt/mobile/dao/MobileDeviceDAO.java | 74 ---- .../MobileDeviceManagementDAOException.java | 80 ----- .../dao/MobileDeviceManagementDAOFactory.java | 27 -- .../mgt/mobile/dao/MobileFeatureDAO.java | 110 ------ .../mobile/dao/impl/MobileFeatureDAOImpl.java | 336 ------------------ .../util/MobileDeviceManagementDAOUtil.java | 139 -------- .../device/mgt/mobile/dto/MobileDevice.java | 125 ------- .../dto/MobileDeviceOperationMapping.java | 86 ----- .../device/mgt/mobile/dto/MobileFeature.java | 73 ---- .../mgt/mobile/dto/MobileFeatureProperty.java | 45 --- .../mgt/mobile/dto/MobileOperation.java | 64 ---- .../mobile/dto/MobileOperationProperty.java | 54 --- .../MobileDeviceManagementDataHolder.java | 67 ---- ...obileDeviceManagementServiceComponent.java | 181 ---------- ...bileDeviceManagementSchemaInitializer.java | 62 ---- .../util/MobileDeviceManagementUtil.java | 320 ----------------- .../MobileDeviceManagementConfigTests.java | 141 -------- .../mgt/mobile/impl/common/DBTypes.java | 29 -- .../impl/common/TestDBConfiguration.java | 90 ----- .../impl/common/TestDBConfigurations.java | 39 -- .../impl/dao/util/MobileDatabaseUtils.java | 111 ------ .../malformed-mobile-config-no-api-config.xml | 41 --- ...-mobile-config-no-api-publisher-config.xml | 42 --- ...malformed-mobile-config-no-apis-config.xml | 42 --- .../malformed-mobile-config-no-ds-config.xml | 42 --- ...malformed-mobile-config-no-jndi-config.xml | 42 --- .../malformed-mobile-config-no-mgt-repo.xml | 42 --- .../MobileDeviceManagementConfigSchema.xsd | 69 ---- .../src/test/resources/log4j.properties | 33 -- .../src/test/resources/sql/h2.sql | 54 --- .../src/test/resources/testdbconfig.xml | 24 -- .../src/test/resources/testng.xml | 27 -- .../pom.xml | 82 ----- .../url/printer/URLPrinterStartupHandler.java | 64 ---- .../internal/URLPrinterDataHolder.java | 42 --- ...PrinterStartupHandlerServiceComponent.java | 73 ---- .../url/printer/URLPrinterStartupHandler.java | 4 +- .../AndroidDeviceManagementService.java | 0 .../impl/android/AndroidDeviceManager.java | 0 .../impl/android/AndroidFeatureManager.java | 0 .../AndroidPolicyMonitoringService.java | 0 .../impl/android/dao/AndroidDAOFactory.java | 0 .../AndroidFeatureManagementDAOException.java | 0 .../dao/impl/AndroidDeviceDAOImpl.java | 0 .../dao/impl/AndroidFeatureDAOImpl.java | 0 .../mobile/impl/android/gcm/GCMResult.java | 0 .../mobile/impl/android/gcm/GCMService.java | 0 .../mgt/mobile/impl/android/gcm/GCMUtil.java | 0 .../android/util/AndroidPluginConstants.java | 0 .../impl/android/util/AndroidPluginUtils.java | 0 .../impl/android/util/AndroidUtils.java | 0 .../WindowsDeviceManagementService.java | 0 .../impl/windows/WindowsDeviceManager.java | 0 .../impl/windows/WindowsFeatureManager.java | 0 .../WindowsPolicyMonitoringService.java | 0 .../impl/windows/dao/WindowsDAOFactory.java | 0 .../WindowsFeatureManagementDAOException.java | 0 .../dao/impl/WindowsDeviceDAOImpl.java | 0 .../dao/impl/WindowsFeatureDAOImpl.java | 0 .../windows/util/WindowsPluginConstants.java | 0 .../impl/windows/util/WindowsPluginUtils.java | 0 .../impl/windows/util/WindowsUtils.java | 0 .../MobileDeviceManagementDataHolder.java | 19 + ...obileDeviceManagementServiceComponent.java | 44 +++ .../mobile-plugins/mobile-base-plugin/pom.xml | 4 +- components/mobile-plugins/pom.xml | 5 +- .../pom.xml | 6 +- .../src/main/resources/build.properties | 0 .../src/main/resources/conf/mobile-config.xml | 0 .../dbscripts/plugins/android/h2.sql | 0 .../dbscripts/plugins/android/mssql.sql | 0 .../dbscripts/plugins/android/mysql.sql | 0 .../dbscripts/plugins/android/oracle.sql | 0 .../dbscripts/plugins/android/postgresql.sql | 0 .../resources/dbscripts/plugins/ios/h2.sql | 0 .../resources/dbscripts/plugins/ios/mssql.sql | 0 .../resources/dbscripts/plugins/ios/mysql.sql | 0 .../dbscripts/plugins/ios/oracle.sql | 0 .../dbscripts/plugins/ios/postgresql.sql | 0 .../dbscripts/plugins/windows/h2.sql | 0 .../dbscripts/plugins/windows/mssql.sql | 0 .../dbscripts/plugins/windows/mysql.sql | 0 .../dbscripts/plugins/windows/oracle.sql | 0 .../dbscripts/plugins/windows/postgresql.sql | 0 .../src/main/resources/p2.inf | 0 .../mobile-base-plugin-feature}/pom.xml | 31 +- .../pom.xml | 5 +- pom.xml | 5 +- 102 files changed, 81 insertions(+), 3893 deletions(-) delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-config.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-apis-config.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-ds-config.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/log4j.properties delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/sql/h2.sql delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testdbconfig.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testng.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManagementService.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManager.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidPolicyMonitoringService.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidDAOFactory.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidFeatureManagementDAOException.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidDeviceDAOImpl.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidFeatureDAOImpl.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginConstants.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginUtils.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidUtils.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManagementService.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManager.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsFeatureManager.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsPolicyMonitoringService.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsDAOFactory.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsFeatureManagementDAOException.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsDeviceDAOImpl.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsFeatureDAOImpl.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginConstants.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginUtils.java (100%) rename components/{device-mgt/org.wso2.carbon.device.mgt.mobile.impl => mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile}/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsUtils.java (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/pom.xml (96%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/build.properties (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/conf/mobile-config.xml (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/h2.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mssql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mysql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/oracle.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/postgresql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/h2.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mssql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mysql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/oracle.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/postgresql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/h2.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mssql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mysql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/oracle.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/postgresql.sql (100%) rename features/{device-mgt => mobile-plugins-feature/mobile-base-plugin-feature}/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf (100%) rename {components/device-mgt => features/mobile-plugins-feature/mobile-base-plugin-feature}/pom.xml (53%) rename features/{device-mgt => mobile-plugins-feature}/pom.xml (89%) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml deleted file mode 100644 index c91d9b7df..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/pom.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - device-mgt - org.wso2.carbon.devicemgt-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.mobile.impl - 2.1.0-SNAPSHOT - bundle - WSO2 Carbon - Mobile Device Management Impl - WSO2 Carbon - Mobile Device Management Impl - http://wso2.org - - - - - org.apache.felix - maven-scr-plugin - - - org.apache.felix - maven-bundle-plugin - 1.4.0 - true - - - ${project.artifactId} - ${project.artifactId} - ${carbon.mobile.device.mgt.version} - Device Management Mobile Impl Bundle - org.wso2.carbon.device.mgt.mobile.internal - - org.osgi.framework, - org.osgi.service.component, - org.apache.commons.logging, - javax.xml.bind.*, - javax.naming, - javax.sql, - javax.xml.parsers, - org.w3c.dom, - org.wso2.carbon.context, - org.wso2.carbon.utils.*, - org.wso2.carbon.device.mgt.common.*, - org.wso2.carbon.ndatasource.core, - org.wso2.carbon.policy.mgt.common.*, - org.wso2.carbon.registry.core, - org.wso2.carbon.registry.core.service, - org.wso2.carbon.registry.core.session, - org.wso2.carbon.registry.api, - org.wso2.carbon.device.mgt.extensions.license.mgt.registry, - com.google.gson.*, - - - !org.wso2.carbon.device.mgt.mobile.internal, - !org.wso2.carbon.device.mgt.mobile.impl, - org.wso2.carbon.device.mgt.mobile.*, - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.18 - - - file:src/test/resources/log4j.properties - - - - src/test/resources/testng.xml - - - - - - - - - org.eclipse.osgi - org.eclipse.osgi - - - org.eclipse.osgi - org.eclipse.osgi.services - - - org.wso2.carbon - org.wso2.carbon.core - - - org.wso2.carbon - org.wso2.carbon.logging - - - org.wso2.carbon - org.wso2.carbon.utils - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.common - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.extensions - - - org.wso2.carbon - org.wso2.carbon.ndatasource.core - - - org.wso2.carbon.devicemgt - org.wso2.carbon.policy.mgt.common - - - org.wso2.carbon.devicemgt - org.wso2.carbon.policy.mgt.core - - - org.wso2.carbon - org.wso2.carbon.registry.api - - - org.wso2.carbon - org.wso2.carbon.registry.core - - - org.testng - testng - - - org.apache.tomcat.wso2 - jdbc-pool - - - com.h2database.wso2 - h2-database-engine - test - - - com.google.code.gson - gson - - - com.google.android.gcm - gcm-server - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java deleted file mode 100644 index 1bf5322da..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/AbstractMobileOperationManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile; - -import org.wso2.carbon.device.mgt.common.*; -import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; -import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; -import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager; - -import java.util.List; - -public abstract class AbstractMobileOperationManager implements OperationManager { - - @Override - public List getOperations(DeviceIdentifier deviceIdentifier) throws OperationManagementException { - return null; - } - - @Override - public int addOperation(Operation operation, List devices) throws - OperationManagementException { - return 1; - } - -} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java deleted file mode 100644 index 649786c43..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceListener.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile; - -public interface DataSourceListener { - - void notifyObserver(); - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java deleted file mode 100644 index 5a9e5b8f4..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/DataSourceNotAvailableException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * * - * * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * * - * * Licensed 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.wso2.carbon.device.mgt.mobile; - -public class DataSourceNotAvailableException extends RuntimeException { - - private String message; - private static final long serialVersionUID = 2021891706072918866L; - - public DataSourceNotAvailableException(String message, Exception nestedException) { - super(message, nestedException); - setErrorMessage(message); - } - - public DataSourceNotAvailableException(String message, Throwable cause) { - super(message, cause); - setErrorMessage(message); - } - - public DataSourceNotAvailableException(String message) { - super(message); - setErrorMessage(message); - } - - public DataSourceNotAvailableException(Throwable cause) { - super(cause); - } - - public String getMessage() { - return message; - } - - public void setErrorMessage(String errorMessage) { - this.message = errorMessage; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java deleted file mode 100644 index ef2871c28..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobileDeviceMgtPluginException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.common; - - -public class MobileDeviceMgtPluginException extends Exception{ - - private static final long serialVersionUID = -2297311387874900305L; - private String errorMessage; - - public String getErrorMessage() { - return errorMessage; - } - - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - - public MobileDeviceMgtPluginException(String msg, Exception nestedEx) { - super(msg, nestedEx); - setErrorMessage(msg); - } - - public MobileDeviceMgtPluginException(String message, Throwable cause) { - super(message, cause); - setErrorMessage(message); - } - - public MobileDeviceMgtPluginException(String msg) { - super(msg); - setErrorMessage(msg); - } - - public MobileDeviceMgtPluginException() { - super(); - } - - public MobileDeviceMgtPluginException(Throwable cause) { - super(cause); - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java deleted file mode 100644 index 67e793fa5..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/common/MobilePluginConstants.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.common; - -public class MobilePluginConstants { - public static final String MOBILE_DB_SCRIPTS_FOLDER = "cdm"; - public static final String MOBILE_CONFIG_REGISTRY_ROOT = "/_system/config"; - - public static final String MEDIA_TYPE_XML = "application/xml"; - public static final String CHARSET_UTF8 = "UTF8"; - public static final String LANGUAGE_CODE_ENGLISH_US = "en_US"; - public static final String LANGUAGE_CODE_ENGLISH_UK = "en_UK"; - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java deleted file mode 100644 index 07123434d..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceConfigurationManager.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config; - -import org.w3c.dom.Document; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; -import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; -import org.wso2.carbon.utils.CarbonUtils; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Unmarshaller; -import java.io.File; - -/** - * Class responsible for the mobile device manager configuration initialization. - */ -public class MobileDeviceConfigurationManager { - - private static final String MOBILE_DEVICE_CONFIG_XML_NAME = "mobile-config.xml"; - private static final String MOBILE_DEVICE_PLUGIN_DIRECTORY = "mobile"; - private static final String DEVICE_MGT_PLUGIN_CONFIGS_DIRECTORY = "device-mgt-plugin-configs"; - private MobileDeviceManagementConfig currentMobileDeviceConfig; - private static MobileDeviceConfigurationManager mobileDeviceConfigManager; - - private final String mobileDeviceMgtConfigXMLPath = - CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + - DEVICE_MGT_PLUGIN_CONFIGS_DIRECTORY + - File.separator + - MOBILE_DEVICE_PLUGIN_DIRECTORY + File.separator + MOBILE_DEVICE_CONFIG_XML_NAME; - - public static MobileDeviceConfigurationManager getInstance() { - if (mobileDeviceConfigManager == null) { - synchronized (MobileDeviceConfigurationManager.class) { - if (mobileDeviceConfigManager == null) { - mobileDeviceConfigManager = new MobileDeviceConfigurationManager(); - } - } - } - return mobileDeviceConfigManager; - } - - public synchronized void initConfig() throws DeviceManagementException { - try { - File mobileDeviceMgtConfig = new File(mobileDeviceMgtConfigXMLPath); - Document doc = MobileDeviceManagementUtil.convertToDocument(mobileDeviceMgtConfig); - JAXBContext mobileDeviceMgmtContext = - JAXBContext.newInstance(MobileDeviceManagementConfig.class); - Unmarshaller unmarshaller = mobileDeviceMgmtContext.createUnmarshaller(); - this.currentMobileDeviceConfig = - (MobileDeviceManagementConfig) unmarshaller.unmarshal(doc); - } catch (Exception e) { - throw new DeviceManagementException( - "Error occurred while initializing Mobile Device Management config", e); - } - } - - public MobileDeviceManagementConfig getMobileDeviceManagementConfig() { - return currentMobileDeviceConfig; - } - - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java deleted file mode 100644 index ced99f955..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -/** - * Represents Mobile Device Mgt configuration. - */ -@XmlRootElement(name = "MobileDeviceMgtConfiguration") -public final class MobileDeviceManagementConfig { - - private MobileDeviceManagementRepository mobileDeviceMgtRepository; - - @XmlElement(name = "ManagementRepository", nillable = false) - public MobileDeviceManagementRepository getMobileDeviceMgtRepository() { - return mobileDeviceMgtRepository; - } - - public void setMobileDeviceMgtRepository( - MobileDeviceManagementRepository mobileDeviceMgtRepository) { - this.mobileDeviceMgtRepository = mobileDeviceMgtRepository; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java deleted file mode 100644 index 88369dd84..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/MobileDeviceManagementRepository.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config; - -import org.wso2.carbon.device.mgt.mobile.config.datasource.DataSourceConfigAdapter; -import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import java.util.List; -import java.util.Map; - -/** - * Class for holding management repository data. - */ -@XmlRootElement(name = "ManagementRepository") -public class MobileDeviceManagementRepository { - - private Map mobileDataSourceConfigMap; - private List mobileDataSourceConfigs; - - public MobileDataSourceConfig getMobileDataSourceConfig(String provider) { - return mobileDataSourceConfigMap.get(provider); - } - - @XmlElement(name = "DataSourceConfigurations") - @XmlJavaTypeAdapter(DataSourceConfigAdapter.class) - public Map getMobileDataSourceConfigMap() { - return mobileDataSourceConfigMap; - } - - public void setMobileDataSourceConfigMap(Map mobileDataSourceConfigMap) { - this.mobileDataSourceConfigMap = mobileDataSourceConfigMap; - } - - public List getMobileDataSourceConfigs() { - return (List) mobileDataSourceConfigMap.values(); - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java deleted file mode 100644 index 71675785c..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/DataSourceConfigAdapter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.config.datasource; - -import javax.xml.bind.annotation.adapters.XmlAdapter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class DataSourceConfigAdapter - extends XmlAdapter> { - - @Override - public Map unmarshal(MobileDataSourceConfigurations mobileDataSourceConfigurations) - throws Exception { - - Map mobileDataSourceConfigMap = new HashMap(); - for (MobileDataSourceConfig mobileDataSourceConfig : mobileDataSourceConfigurations - .getMobileDataSourceConfigs()) { - mobileDataSourceConfigMap.put(mobileDataSourceConfig.getType(), mobileDataSourceConfig); - } - return mobileDataSourceConfigMap; - } - - @Override - public MobileDataSourceConfigurations marshal(Map mobileDataSourceConfigMap) - throws Exception { - - MobileDataSourceConfigurations mobileDataSourceConfigurations = new MobileDataSourceConfigurations(); - mobileDataSourceConfigurations.setMobileDataSourceConfigs( - (List) mobileDataSourceConfigMap.values()); - - return mobileDataSourceConfigurations; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java deleted file mode 100644 index 603adcedd..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/JNDILookupDefinition.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config.datasource; - -import javax.xml.bind.annotation.*; -import java.util.List; - -/** - * Class for hold JndiLookupDefinition of mobile-config.xml at parsing with JAXB. - */ -@XmlRootElement(name = "JndiLookupDefinition") -public class JNDILookupDefinition { - - private String jndiName; - private List jndiProperties; - - @XmlElement(name = "Name", nillable = false) - public String getJndiName() { - return jndiName; - } - - public void setJndiName(String jndiName) { - this.jndiName = jndiName; - } - - @XmlElementWrapper(name = "Environment", nillable = false) - @XmlElement(name = "Property", nillable = false) - public List getJndiProperties() { - return jndiProperties; - } - - public void setJndiProperties(List jndiProperties) { - this.jndiProperties = jndiProperties; - } - - @XmlRootElement(name = "Property") - public static class JNDIProperty { - - private String name; - - private String value; - - @XmlAttribute(name = "Name") - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @XmlValue - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - } - -} - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java deleted file mode 100644 index 869aaf12e..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.config.datasource; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -/** - * Class for holding data source configuration in mobile-config.xml at parsing with JAXB. - */ -@XmlRootElement(name = "DataSourceConfiguration") -public class MobileDataSourceConfig { - - private JNDILookupDefinition jndiLookupDefinition; - private String type; - - @XmlElement(name = "JndiLookupDefinition", nillable = true) - public JNDILookupDefinition getJndiLookupDefinition() { - return jndiLookupDefinition; - } - - public void setJndiLookupDefinition(JNDILookupDefinition jndiLookupDefinition) { - this.jndiLookupDefinition = jndiLookupDefinition; - } - - @XmlAttribute(name = "type") - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java deleted file mode 100644 index 17e80f5bf..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/config/datasource/MobileDataSourceConfigurations.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.config.datasource; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.util.List; - -@XmlRootElement(name = "DataSourceConfigurations") -@XmlAccessorType(XmlAccessType.FIELD) -public class MobileDataSourceConfigurations { - - @XmlElement(name = "DataSourceConfiguration", nillable = true) - private List mobileDataSourceConfigs; - - public List getMobileDataSourceConfigs() { - return mobileDataSourceConfigs; - } - - public void setMobileDataSourceConfigs(List mobileDataSourceConfigs) { - this.mobileDataSourceConfigs = mobileDataSourceConfigs; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java deleted file mode 100644 index 32bcb8de7..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/AbstractMobileDeviceManagementDAOFactory.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; -import org.wso2.carbon.device.mgt.mobile.config.datasource.JNDILookupDefinition; -import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; -import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; - -import javax.sql.DataSource; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; - -/** - * Factory class used to create MobileDeviceManagement related DAO objects. - */ -public abstract class AbstractMobileDeviceManagementDAOFactory implements MobileDeviceManagementDAOFactory { - - private static final Log log = LogFactory.getLog(AbstractMobileDeviceManagementDAOFactory.class); - private static Map dataSourceMap = new HashMap<>(); - private static boolean isInitialized; - - public static void init(Map mobileDataSourceConfigMap) - throws MobileDeviceMgtPluginException { - DataSource dataSource; - for (String pluginType : mobileDataSourceConfigMap.keySet()) { - if (dataSourceMap.get(pluginType) == null) { - dataSource = AbstractMobileDeviceManagementDAOFactory.resolveDataSource(mobileDataSourceConfigMap.get - (pluginType)); - dataSourceMap.put(pluginType, dataSource); - } - } - isInitialized = true; - } - - public static void init(String key, MobileDataSourceConfig mobileDataSourceConfig) throws - MobileDeviceMgtPluginException { - DataSource dataSource = AbstractMobileDeviceManagementDAOFactory.resolveDataSource(mobileDataSourceConfig); - dataSourceMap.put(key, dataSource); - } - - /** - * Resolve data source from the data source definition. - * - * @param config Mobile data source configuration - * @return data source resolved from the data source definition - */ - public static DataSource resolveDataSource(MobileDataSourceConfig config) { - DataSource dataSource = null; - if (config == null) { - throw new RuntimeException("Device Management Repository data source configuration " + - "is null and thus, is not initialized"); - } - JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition(); - if (jndiConfig != null) { - if (log.isDebugEnabled()) { - log.debug("Initializing Device Management Repository data source using the JNDI " + - "Lookup Definition"); - } - List jndiPropertyList = - jndiConfig.getJndiProperties(); - if (jndiPropertyList != null) { - Hashtable jndiProperties = new Hashtable(); - for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) { - jndiProperties.put(prop.getName(), prop.getValue()); - } - dataSource = - MobileDeviceManagementDAOUtil - .lookupDataSource(jndiConfig.getJndiName(), jndiProperties); - } else { - dataSource = MobileDeviceManagementDAOUtil - .lookupDataSource(jndiConfig.getJndiName(), null); - } - } - return dataSource; - } - - public static Map getDataSourceMap() { - return dataSourceMap; - } - -} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java deleted file mode 100644 index 161594273..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceDAO.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; - -import org.wso2.carbon.device.mgt.mobile.dto.MobileDevice; -import java.util.List; - -/** - * This class represents the key operations associated with persisting mobile-device related - * information. - */ -public interface MobileDeviceDAO { - - /** - * Fetches a MobileDevice from MDM database. - * - * @param mblDeviceId Id of the Mobile-Device. - * @return MobileDevice corresponding to given device-id. - * @throws MobileDeviceManagementDAOException - */ - MobileDevice getMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException; - - /** - * Adds a new MobileDevice to the MDM database. - * - * @param mobileDevice MobileDevice to be added. - * @return The status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean addMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException; - - /** - * Updates MobileDevice information in MDM database. - * - * @param mobileDevice MobileDevice to be updated. - * @return The status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean updateMobileDevice(MobileDevice mobileDevice) throws MobileDeviceManagementDAOException; - - /** - * Deletes a given MobileDevice from MDM database. - * - * @param mblDeviceId Id of MobileDevice to be deleted. - * @return The status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean deleteMobileDevice(String mblDeviceId) throws MobileDeviceManagementDAOException; - - /** - * Fetches all MobileDevices from MDM database. - * - * @return List of MobileDevices. - * @throws MobileDeviceManagementDAOException - */ - List getAllMobileDevices() throws MobileDeviceManagementDAOException; - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java deleted file mode 100644 index 0b04818d9..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOException.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; - -/** - * Custom exception class for mobile device specific data access related exceptions. - */ -public class MobileDeviceManagementDAOException extends Exception { - - private String message; - private static final long serialVersionUID = 2021891706072918865L; - - /** - * Constructs a new MobileDeviceManagementDAOException with the specified detail message and - * nested exception. - * - * @param message error message - * @param nestedException exception - */ - public MobileDeviceManagementDAOException(String message, Exception nestedException) { - super(message, nestedException); - setErrorMessage(message); - } - - /** - * Constructs a new MobileDeviceManagementDAOException with the specified detail message - * and cause. - * - * @param message the detail message. - * @param cause the cause of this exception. - */ - public MobileDeviceManagementDAOException(String message, Throwable cause) { - super(message, cause); - setErrorMessage(message); - } - - /** - * Constructs a new MobileDeviceManagementDAOException with the specified detail message. - * - * @param message the detail message. - */ - public MobileDeviceManagementDAOException(String message) { - super(message); - setErrorMessage(message); - } - - /** - * Constructs a new MobileDeviceManagementDAOException with the specified and cause. - * - * @param cause the cause of this exception. - */ - public MobileDeviceManagementDAOException(Throwable cause) { - super(cause); - } - - public String getMessage() { - return message; - } - - public void setErrorMessage(String errorMessage) { - this.message = errorMessage; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java deleted file mode 100644 index 37a5c311c..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileDeviceManagementDAOFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; - -public interface MobileDeviceManagementDAOFactory { - - MobileDeviceDAO getMobileDeviceDAO(); - - MobileFeatureDAO getMobileFeatureDAO(); - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java deleted file mode 100644 index 55c77424b..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/MobileFeatureDAO.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao; - -import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; - -import java.util.List; - -/** - * This class represents the key operations associated with persisting mobile feature related - * information. - */ -public interface MobileFeatureDAO { - - /** - * Adds a new MobileFeature to Mobile-Feature table. - * - * @param mobileFeature MobileFeature object that holds data related to the feature to be inserted. - * @return boolean status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean addFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException; - - /** - * Adda a list of MobileFeatures to Mobile-Feature table. - * - * @param mobileFeatures List of MobileFeature objects. - * @return boolean status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean addFeatures(List mobileFeatures) throws MobileDeviceManagementDAOException; - - /** - * Updates a MobileFeature in Mobile-Feature table. - * - * @param mobileFeature MobileFeature object that holds data has to be updated. - * @return The status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean updateFeature(MobileFeature mobileFeature) throws MobileDeviceManagementDAOException; - - /** - * Deletes a MobileFeature from Mobile-Feature table when the feature id is given. - * - * @param mblFeatureId MobileFeature id of the MobileFeature to be deleted. - * @return The status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean deleteFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException; - - /** - * Deletes a MobileFeature from Mobile-Feature table when the feature code is given. - * - * @param mblFeatureCode MobileFeature code of the feature to be deleted. - * @return The status of the operation. - * @throws MobileDeviceManagementDAOException - */ - boolean deleteFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException; - - /** - * Retrieves a given MobileFeature from Mobile-Feature table when the feature id is given. - * - * @param mblFeatureId Feature id of the feature to be retrieved. - * @return MobileFeature object that holds data of the feature represented by featureId. - * @throws MobileDeviceManagementDAOException - */ - MobileFeature getFeatureById(int mblFeatureId) throws MobileDeviceManagementDAOException; - - /** - * Retrieves a given MobileFeature from Mobile-Feature table when the feature code is given. - * - * @param mblFeatureCode Feature code of the feature to be retrieved. - * @return MobileFeature object that holds data of the feature represented by featureCode. - * @throws MobileDeviceManagementDAOException - */ - MobileFeature getFeatureByCode(String mblFeatureCode) throws MobileDeviceManagementDAOException; - - /** - * Retrieves all MobileFeatures of a MobileDevice type from Mobile-Feature table. - * - * @param deviceType MobileDevice type of the MobileFeatures to be retrieved - * @return MobileFeature object list. - * @throws MobileDeviceManagementDAOException - */ - List getFeatureByDeviceType(String deviceType) throws MobileDeviceManagementDAOException; - - /** - * Retrieve all the MobileFeatures from Mobile-Feature table. - * - * @return MobileFeature object list. - * @throws MobileDeviceManagementDAOException - */ - List getAllFeatures() throws MobileDeviceManagementDAOException; -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java deleted file mode 100644 index 86a940fd6..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/impl/MobileFeatureDAOImpl.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2014, 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.wso2.carbon.device.mgt.mobile.dao.impl; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; -import org.wso2.carbon.device.mgt.mobile.dao.MobileFeatureDAO; -import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; -import org.wso2.carbon.device.mgt.mobile.dto.MobileFeature; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -/** - * Implementation of MobileFeatureDAO. - */ -public class MobileFeatureDAOImpl implements MobileFeatureDAO { - - private DataSource dataSource; - private static final Log log = LogFactory.getLog(MobileFeatureDAOImpl.class); - - public MobileFeatureDAOImpl(DataSource dataSource) { - this.dataSource = dataSource; - } - - @Override - public boolean addFeature(MobileFeature mobileFeature) - throws MobileDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = this.getConnection(); - String createDBQuery = - "INSERT INTO AD_FEATURE(CODE, NAME, DESCRIPTION, DEVICE_TYPE) VALUES (?, ?, ?, ?)"; - - stmt = conn.prepareStatement(createDBQuery); - stmt.setString(1, mobileFeature.getCode()); - stmt.setString(2, mobileFeature.getName()); - stmt.setString(3, mobileFeature.getDescription()); - stmt.setString(4, mobileFeature.getDeviceType()); - int rows = stmt.executeUpdate(); - if (rows > 0) { - if (log.isDebugEnabled()) { - log.debug("Added a new MobileFeature " + mobileFeature.getCode() + " to the MDM database."); - } - status = true; - } - } catch (SQLException e) { - String msg = "Error occurred while adding feature code - '" + - mobileFeature.getCode() + "' to feature table"; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); - } - return status; - } - - @Override - public boolean addFeatures(List mobileFeatures) throws MobileDeviceManagementDAOException { - return false; - } - - @Override - public boolean updateFeature(MobileFeature mobileFeature) - throws MobileDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = this.getConnection(); - String updateDBQuery = - "UPDATE AD_FEATURE SET CODE = ?, NAME = ?, DESCRIPTION = ?, DEVICE_TYPE = ?" + - " WHERE ID = ?"; - stmt = conn.prepareStatement(updateDBQuery); - stmt.setString(1, mobileFeature.getCode()); - stmt.setString(2, mobileFeature.getName()); - stmt.setString(3, mobileFeature.getDescription()); - stmt.setString(4, mobileFeature.getDeviceType()); - stmt.setInt(5, mobileFeature.getId()); - int rows = stmt.executeUpdate(); - if (rows > 0) { - status = true; - if (log.isDebugEnabled()) { - log.debug("Updated MobileFeature " + mobileFeature.getCode()); - } - } - } catch (SQLException e) { - String msg = "Error occurred while updating the feature with feature code - '" + - mobileFeature.getId() + "'"; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); - } - return status; - } - - @Override - public boolean deleteFeatureByCode(String mblFeatureCode) - throws MobileDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = this.getConnection(); - String deleteDBQuery = - "DELETE FROM AD_FEATURE WHERE CODE = ?"; - stmt = conn.prepareStatement(deleteDBQuery); - stmt.setString(1, mblFeatureCode); - int rows = stmt.executeUpdate(); - if (rows > 0) { - status = true; - if (log.isDebugEnabled()) { - log.debug("Deleted MobileFeature code " + mblFeatureCode + " from the MDM database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while deleting feature with code - " + mblFeatureCode; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); - } - return status; - } - - @Override - public boolean deleteFeatureById(int mblFeatureId) - throws MobileDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = this.getConnection(); - String deleteDBQuery = - "DELETE FROM AD_FEATURE WHERE ID = ?"; - stmt = conn.prepareStatement(deleteDBQuery); - stmt.setInt(1, mblFeatureId); - int rows = stmt.executeUpdate(); - if (rows > 0) { - status = true; - if (log.isDebugEnabled()) { - log.debug("Deleted MobileFeature id " + mblFeatureId + " from the MDM database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while deleting feature with id - " + mblFeatureId; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, null); - } - return status; - } - - @Override - public MobileFeature getFeatureByCode(String mblFeatureCode) - throws MobileDeviceManagementDAOException { - Connection conn = null; - PreparedStatement stmt = null; - MobileFeature mobileFeature = null; - ResultSet resultSet = null; - try { - conn = this.getConnection(); - String selectDBQuery = - "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE " + - "WHERE CODE = ?"; - stmt = conn.prepareStatement(selectDBQuery); - stmt.setString(1, mblFeatureCode); - resultSet = stmt.executeQuery(); - if (resultSet.next()) { - mobileFeature = new MobileFeature(); - mobileFeature.setId(resultSet.getInt(1)); - mobileFeature.setCode(resultSet.getString(2)); - mobileFeature.setName(resultSet.getString(3)); - mobileFeature.setDescription(resultSet.getString(4)); - mobileFeature.setDeviceType(resultSet.getString(5)); - if (log.isDebugEnabled()) { - log.debug("Fetched MobileFeature " + mblFeatureCode + " from the MDM database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while fetching feature code - '" + mblFeatureCode + "'"; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); - } - return mobileFeature; - } - - @Override - public MobileFeature getFeatureById(int mblFeatureId) - throws MobileDeviceManagementDAOException { - Connection conn = null; - PreparedStatement stmt = null; - MobileFeature mobileFeature = null; - ResultSet resultSet = null; - try { - conn = this.getConnection(); - String selectDBQuery = - "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE" + - " WHERE ID = ?"; - stmt = conn.prepareStatement(selectDBQuery); - stmt.setInt(1, mblFeatureId); - resultSet = stmt.executeQuery(); - if (resultSet.next()) { - mobileFeature = new MobileFeature(); - mobileFeature.setId(resultSet.getInt(1)); - mobileFeature.setCode(resultSet.getString(2)); - mobileFeature.setName(resultSet.getString(3)); - mobileFeature.setDescription(resultSet.getString(4)); - mobileFeature.setDeviceType(resultSet.getString(5)); - if (log.isDebugEnabled()) { - log.debug("Fetched MobileFeatureId" + mblFeatureId + " from the MDM database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while fetching feature id - '" + mblFeatureId + "'"; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); - } - return mobileFeature; - } - - @Override - public List getAllFeatures() throws MobileDeviceManagementDAOException { - Connection conn = null; - PreparedStatement stmt = null; - MobileFeature mobileFeature; - List mobileFeatures = new ArrayList(); - ResultSet resultSet = null; - try { - conn = this.getConnection(); - String selectDBQuery = - "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE"; - stmt = conn.prepareStatement(selectDBQuery); - resultSet = stmt.executeQuery(); - while (resultSet.next()) { - mobileFeature = new MobileFeature(); - mobileFeature.setId(resultSet.getInt(1)); - mobileFeature.setCode(resultSet.getString(2)); - mobileFeature.setName(resultSet.getString(3)); - mobileFeature.setDescription(resultSet.getString(4)); - mobileFeature.setDeviceType(resultSet.getString(5)); - mobileFeatures.add(mobileFeature); - } - if (log.isDebugEnabled()) { - log.debug("Fetched all MobileFeatures from the MDM database."); - } - return mobileFeatures; - } catch (SQLException e) { - String msg = "Error occurred while fetching all features.'"; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); - } - } - - @Override - public List getFeatureByDeviceType(String deviceType) throws MobileDeviceManagementDAOException { - Connection conn = null; - PreparedStatement stmt = null; - MobileFeature mobileFeature; - List mobileFeatures = new ArrayList<>(); - ResultSet resultSet = null; - try { - conn = this.getConnection(); - String selectDBQuery = - "SELECT ID, CODE, NAME, DESCRIPTION, DEVICE_TYPE FROM AD_FEATURE" + - " WHERE DEVICE_TYPE = ?"; - stmt = conn.prepareStatement(selectDBQuery); - stmt.setString(1, deviceType); - resultSet = stmt.executeQuery(); - while (resultSet.next()) { - mobileFeature = new MobileFeature(); - mobileFeature.setId(resultSet.getInt(1)); - mobileFeature.setCode(resultSet.getString(2)); - mobileFeature.setName(resultSet.getString(3)); - mobileFeature.setDescription(resultSet.getString(4)); - mobileFeature.setDeviceType(resultSet.getString(5)); - mobileFeatures.add(mobileFeature); - } - if (log.isDebugEnabled()) { - log.debug("Fetched all MobileFeatures of type " + deviceType + " from the MDM" + - " database."); - } - return mobileFeatures; - } catch (SQLException e) { - String msg = "Error occurred while fetching all features.'"; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } finally { - MobileDeviceManagementDAOUtil.cleanupResources(conn, stmt, resultSet); - } - } - - private Connection getConnection() throws MobileDeviceManagementDAOException { - try { - return dataSource.getConnection(); - } catch (SQLException e) { - String msg = "Error occurred while obtaining a connection from the mobile specific " + - "datasource."; - log.error(msg, e); - throw new MobileDeviceManagementDAOException(msg, e); - } - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java deleted file mode 100644 index 0f72e82e9..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dao/util/MobileDeviceManagementDAOUtil.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dao.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; -import org.wso2.carbon.device.mgt.mobile.config.datasource.JNDILookupDefinition; -import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; -import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementSchemaInitializer; - -import javax.naming.InitialContext; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Hashtable; -import java.util.List; - -/** - * Utility method required by MobileDeviceManagement DAO classes. - */ -public class MobileDeviceManagementDAOUtil { - - private static final Log log = LogFactory.getLog(MobileDeviceManagementDAOUtil.class); - - public static DataSource lookupDataSource(String dataSourceName, - final Hashtable jndiProperties){ - - try { - if (jndiProperties == null || jndiProperties.isEmpty()) { - return (DataSource) InitialContext.doLookup(dataSourceName); - } - final InitialContext context = new InitialContext(jndiProperties); - return (DataSource) context.lookup(dataSourceName); - } catch (Exception e) { - String msg = "Error in looking up data source: " + e.getMessage(); - log.error(msg, e); - throw new RuntimeException(msg + e.getMessage(), e); - } - } - - 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); - } - - /** - * Creates the mobile device management schema. - * - * @param dataSource Mobile data source - */ - public static void setupMobileDeviceManagementSchema(DataSource dataSource, String pluginType) throws MobileDeviceMgtPluginException { - MobileDeviceManagementSchemaInitializer initializer = - new MobileDeviceManagementSchemaInitializer(dataSource, pluginType); - log.info("Initializing mobile device management repository database schema for : " + pluginType); - try { - initializer.createRegistryDatabase(); - } catch (Exception e) { - throw new MobileDeviceMgtPluginException("Error occurred while initializing Mobile Device " + - "Management database schema", e); - } - } - - - /** - * Resolve data source from the data source definition - * - * @param config data source configuration - * @return data source resolved from the data source definition - */ - private static DataSource resolveDataSource(MobileDataSourceConfig config) { - DataSource dataSource = null; - if (config == null) { - throw new RuntimeException( - "data source configuration " + "is null and " + - "thus, is not initialized"); - } - JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition(); - if (jndiConfig != null) { - if (log.isDebugEnabled()) { - log.debug("Initializing data source using the JNDI " + - "Lookup Definition"); - } - List jndiPropertyList = - jndiConfig.getJndiProperties(); - if (jndiPropertyList != null) { - Hashtable jndiProperties = new Hashtable(); - for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) { - jndiProperties.put(prop.getName(), prop.getValue()); - } - dataSource = MobileDeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), jndiProperties); - } else { - dataSource = MobileDeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), null); - } - } - return dataSource; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java deleted file mode 100644 index 185168da4..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDevice.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -/** - * DTO of MobileDevice. - */ -public class MobileDevice implements Serializable { - - private String mobileDeviceId; - private String osVersion; - private String model; - private String vendor; - private String latitude; - private String longitude; - private String imei; - private String imsi; - private String serial; - private Map deviceProperties; - - public MobileDevice() { - this.deviceProperties = new HashMap<>(); - } - - public String getMobileDeviceId() { - return mobileDeviceId; - } - - public void setMobileDeviceId(String mobileDeviceId) { - this.mobileDeviceId = mobileDeviceId; - } - - public String getOsVersion() { - return osVersion; - } - - public void setOsVersion(String osVersion) { - this.osVersion = osVersion; - } - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - public String getVendor() { - return vendor; - } - - public void setVendor(String vendor) { - this.vendor = vendor; - } - - public String getLatitude() { - return latitude; - } - - public void setLatitude(String latitude) { - this.latitude = latitude; - } - - public String getLongitude() { - return longitude; - } - - public void setLongitude(String longitude) { - this.longitude = longitude; - } - - public String getImei() { - return imei; - } - - public void setImei(String imei) { - this.imei = imei; - } - - public String getImsi() { - return imsi; - } - - public void setImsi(String imsi) { - this.imsi = imsi; - } - - public String getSerial() { - return serial; - } - - public void setSerial(String serial) { - this.serial = serial; - } - - public Map getDeviceProperties() { - return deviceProperties; - } - - public void setDeviceProperties(Map deviceProperties) { - this.deviceProperties = deviceProperties; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java deleted file mode 100644 index 0ae7e68fa..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileDeviceOperationMapping.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; - -/** - * DTO of Mobile Device Operation Mappings. - */ -public class MobileDeviceOperationMapping { - - private String deviceId; - private int operationId; - private long sentDate; - private long receivedDate; - private Status status; - - public enum Status { - NEW, INPROGRESS, COMPLETED - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public void setStatus(String status) { - if(Status.NEW.name().equals(status)){ - this.status = Status.NEW; - }else if(Status.INPROGRESS.name().equals(status)){ - this.status = Status.INPROGRESS; - }else if(Status.COMPLETED.name().equals(status)){ - this.status = Status.COMPLETED; - } - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public int getOperationId() { - return operationId; - } - - public void setOperationId(int operationId) { - this.operationId = operationId; - } - - public long getSentDate() { - return sentDate; - } - - public void setSentDate(long sentDate) { - this.sentDate = sentDate; - } - - public long getReceivedDate() { - return receivedDate; - } - - public void setReceivedDate(long receivedDate) { - this.receivedDate = receivedDate; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java deleted file mode 100644 index 9ec5d30b3..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeature.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; - -import java.io.Serializable; - -/** - * DTO of Mobile features. - */ -public class MobileFeature implements Serializable { - - private int id; - private String deviceType; - private String code; - private String name; - private String description; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getDeviceType() { - return deviceType; - } - - public void setDeviceType(String deviceType) { - this.deviceType = deviceType; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java deleted file mode 100644 index cc99849de..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileFeatureProperty.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; - -/** - * DTO of Mobile feature property. Represents a property of a mobile feature. - */ -public class MobileFeatureProperty { - - private String property; - private Integer featureID; - - public Integer getFeatureID() { - return featureID; - } - - public void setFeatureID(Integer featureID) { - this.featureID = featureID; - } - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java deleted file mode 100644 index 7c0b9040c..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperation.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; - -import java.util.List; - -/** - * DTO of MobileOperation. - */ -public class MobileOperation { - - private int operationId; - private String featureCode; - private long createdDate; - private List properties; - - public int getOperationId() { - return operationId; - } - - public void setOperationId(int operationId) { - this.operationId = operationId; - } - - public List getProperties() { - return properties; - } - - public void setProperties(List properties) { - this.properties = properties; - } - - public String getFeatureCode() { - return featureCode; - } - - public void setFeatureCode(String featureCode) { - this.featureCode = featureCode; - } - - public long getCreatedDate() { - return createdDate; - } - - public void setCreatedDate(long createdDate) { - this.createdDate = createdDate; - } -} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java deleted file mode 100644 index d18126aff..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/dto/MobileOperationProperty.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.dto; - -/** - * DTO of Mobile Operation property. - */ -public class MobileOperationProperty { - - private int operationId; - private String property; - private String value; - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public int getOperationId() { - return operationId; - } - - public void setOperationId(int operationId) { - this.operationId = operationId; - } - - public String getProperty() { - return property; - } - - public void setProperty(String property) { - this.property = property; - } - -} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java deleted file mode 100644 index 869904e81..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.internal; - -import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; -import org.wso2.carbon.device.mgt.mobile.impl.android.gcm.GCMService; -import org.wso2.carbon.registry.core.service.RegistryService; - -/** - * DataHolder class of Mobile plugins component. - */ -public class MobileDeviceManagementDataHolder { - - private RegistryService registryService; - private DeviceManagementService androidDeviceManagementService; - private GCMService gcmService; - - private static MobileDeviceManagementDataHolder thisInstance = new MobileDeviceManagementDataHolder(); - - private MobileDeviceManagementDataHolder() { - } - - public static MobileDeviceManagementDataHolder getInstance() { - return thisInstance; - } - - public RegistryService getRegistryService() { - return registryService; - } - - public void setRegistryService(RegistryService registryService) { - this.registryService = registryService; - } - - public DeviceManagementService getAndroidDeviceManagementService() { - return androidDeviceManagementService; - } - - public void setAndroidDeviceManagementService( - DeviceManagementService androidDeviceManagementService) { - this.androidDeviceManagementService = androidDeviceManagementService; - } - - public GCMService getGCMService() { - return gcmService; - } - - public void setGCMService(GCMService gcmService) { - this.gcmService = gcmService; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java deleted file mode 100644 index 92404b67a..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -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; -import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; -import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceConfigurationManager; -import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceManagementConfig; -import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; -import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; -import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; -import org.wso2.carbon.device.mgt.mobile.impl.android.AndroidDeviceManagementService; -import org.wso2.carbon.device.mgt.mobile.impl.android.AndroidPolicyMonitoringService; -import org.wso2.carbon.device.mgt.mobile.impl.android.gcm.GCMService; -import org.wso2.carbon.device.mgt.mobile.impl.windows.WindowsDeviceManagementService; -import org.wso2.carbon.device.mgt.mobile.impl.windows.WindowsPolicyMonitoringService; -import org.wso2.carbon.ndatasource.core.DataSourceService; -import org.wso2.carbon.policy.mgt.common.spi.PolicyMonitoringService; -import org.wso2.carbon.registry.core.service.RegistryService; - -import java.util.Map; - -/** - * @scr.component name="org.wso2.carbon.device.mgt.mobile.impl.internal.MobileDeviceManagementServiceComponent" - * immediate="true" - * @scr.reference name="org.wso2.carbon.ndatasource" - * interface="org.wso2.carbon.ndatasource.core.DataSourceService" - * cardinality="1..1" - * policy="dynamic" - * bind="setDataSourceService" - * unbind="unsetDataSourceService" - * @scr.reference name="registry.service" - * interface="org.wso2.carbon.registry.core.service.RegistryService" cardinality="0..1" - * policy="dynamic" bind="setRegistryService" unbind="unsetRegistryService" - *

      - * Adding reference to API Manager Configuration service is an unavoidable hack to get rid of NPEs thrown while - * initializing APIMgtDAOs attempting to register APIs programmatically. APIMgtDAO needs to be proper cleaned up - * to avoid as an ideal fix - */ -public class MobileDeviceManagementServiceComponent { - - private ServiceRegistration androidServiceRegRef; - private ServiceRegistration windowsServiceRegRef; - private ServiceRegistration gcmServiceRegRef; - - private static final Log log = LogFactory.getLog(MobileDeviceManagementServiceComponent.class); - - protected void activate(ComponentContext ctx) { - - if (log.isDebugEnabled()) { - log.debug("Activating Mobile Device Management Service Component"); - } - try { - BundleContext bundleContext = ctx.getBundleContext(); - - /* Initialize the data source configuration */ - MobileDeviceConfigurationManager.getInstance().initConfig(); - MobileDeviceManagementConfig config = MobileDeviceConfigurationManager.getInstance() - .getMobileDeviceManagementConfig(); - Map dsConfigMap = - config.getMobileDeviceMgtRepository().getMobileDataSourceConfigMap(); - - AbstractMobileDeviceManagementDAOFactory.init(dsConfigMap); - - String setupOption = System.getProperty("setup"); - if (setupOption != null) { - if (log.isDebugEnabled()) { - log.debug( - "-Dsetup is enabled. Mobile Device management repository schema initialization is about " + - "to begin"); - } - try { - for (String pluginType : dsConfigMap.keySet()) { - MobileDeviceManagementDAOUtil - .setupMobileDeviceManagementSchema(AbstractMobileDeviceManagementDAOFactory.getDataSourceMap - ().get(pluginType), pluginType); - } - } catch (MobileDeviceMgtPluginException e) { - log.error("Exception occurred while initializing mobile device management database schema", e); - } - } - DeviceManagementService androidDeviceManagementService = new AndroidDeviceManagementService(); - GCMService gcmService = new GCMService(); - - androidServiceRegRef = - bundleContext.registerService(DeviceManagementService.class.getName(), - androidDeviceManagementService, null); - windowsServiceRegRef = - bundleContext.registerService(DeviceManagementService.class.getName(), - new WindowsDeviceManagementService(), null); - - gcmServiceRegRef = - bundleContext.registerService(GCMService.class.getName(), gcmService, null); - - - // Policy management service - - bundleContext.registerService(PolicyMonitoringService.class, - new AndroidPolicyMonitoringService(), null); - bundleContext.registerService(PolicyMonitoringService.class, - new WindowsPolicyMonitoringService(), null); - - MobileDeviceManagementDataHolder.getInstance().setAndroidDeviceManagementService( - androidDeviceManagementService); - MobileDeviceManagementDataHolder.getInstance().setGCMService(gcmService); - if (log.isDebugEnabled()) { - log.debug("Mobile Device Management Service Component has been successfully activated"); - } - } catch (Throwable e) { - log.error("Error occurred while activating Mobile Device Management Service Component", e); - } - } - - protected void deactivate(ComponentContext ctx) { - if (log.isDebugEnabled()) { - log.debug("De-activating Mobile Device Management Service Component"); - } - try { - if (androidServiceRegRef != null) { - androidServiceRegRef.unregister(); - } - if (windowsServiceRegRef != null) { - windowsServiceRegRef.unregister(); - } - if (gcmServiceRegRef != null) { - gcmServiceRegRef.unregister(); - } - if (log.isDebugEnabled()) { - log.debug( - "Mobile Device Management Service Component has been successfully de-activated"); - } - } catch (Throwable e) { - log.error("Error occurred while de-activating Mobile Device Management bundle", e); - } - } - - protected void setDataSourceService(DataSourceService dataSourceService) { - /* This is to avoid mobile device management component getting initialized before the underlying datasources - are registered */ - if (log.isDebugEnabled()) { - log.debug("Data source service set to mobile service component"); - } - } - - protected void unsetDataSourceService(DataSourceService dataSourceService) { - //do nothing - } - - protected void setRegistryService(RegistryService registryService) { - if (log.isDebugEnabled()) { - log.debug("RegistryService acquired"); - } - MobileDeviceManagementDataHolder.getInstance().setRegistryService(registryService); - } - - protected void unsetRegistryService(RegistryService registryService) { - MobileDeviceManagementDataHolder.getInstance().setRegistryService(null); - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java deleted file mode 100644 index f0071a85f..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementSchemaInitializer.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.mobile.common.MobilePluginConstants; -import org.wso2.carbon.utils.CarbonUtils; -import org.wso2.carbon.utils.dbcreator.DatabaseCreator; - -import javax.sql.DataSource; -import java.io.File; - -/** - * - * Provides methods for initializing the database script. - * - */ -public final class MobileDeviceManagementSchemaInitializer extends DatabaseCreator { - - private static final Log log = LogFactory.getLog(MobileDeviceManagementSchemaInitializer.class); - private static final String setupSQLScriptBaseLocation = - CarbonUtils.getCarbonHome() + File.separator + "dbscripts" + File.separator - + MobilePluginConstants.MOBILE_DB_SCRIPTS_FOLDER + - File.separator + "plugins" + File.separator; - private String pluginType; - - public String getPluginType() { - return pluginType; - } - - public MobileDeviceManagementSchemaInitializer(DataSource dataSource, String pType) { - super(dataSource); - this.pluginType = pType; - } - - protected String getDbScriptLocation(String databaseType) { - String scriptName = databaseType + ".sql"; - String scriptLocation = setupSQLScriptBaseLocation + this.getPluginType() + File.separator + scriptName; - if (log.isDebugEnabled()) { - log.debug("Loading database script from :" + scriptLocation); - } - return scriptLocation; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java deleted file mode 100644 index 73612a365..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/util/MobileDeviceManagementUtil.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Document; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.common.Device; -import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.Feature; -import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; -import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; -import org.wso2.carbon.device.mgt.mobile.common.MobilePluginConstants; -import org.wso2.carbon.device.mgt.mobile.dto.*; -import org.wso2.carbon.device.mgt.mobile.internal.MobileDeviceManagementDataHolder; -import org.wso2.carbon.registry.api.RegistryException; -import org.wso2.carbon.registry.api.Resource; -import org.wso2.carbon.registry.core.Registry; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.File; -import java.util.*; - -/** - * Provides utility methods required by the mobile device management bundle. - */ -public class MobileDeviceManagementUtil { - - private static final Log log = LogFactory.getLog(MobileDeviceManagementUtil.class); - private static final String MOBILE_DEVICE_IMEI = "IMEI"; - private static final String MOBILE_DEVICE_IMSI = "IMSI"; - private static final String MOBILE_DEVICE_VENDOR = "VENDOR"; - private static final String MOBILE_DEVICE_OS_VERSION = "OS_VERSION"; - private static final String MOBILE_DEVICE_MODEL = "DEVICE_MODEL"; - private static final String MOBILE_DEVICE_LATITUDE = "LATITUDE"; - private static final String MOBILE_DEVICE_LONGITUDE = "LONGITUDE"; - private static final String MOBILE_DEVICE_SERIAL = "SERIAL"; - - public static Document convertToDocument(File file) throws DeviceManagementException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - try { - DocumentBuilder docBuilder = factory.newDocumentBuilder(); - return docBuilder.parse(file); - } catch (Exception e) { - throw new DeviceManagementException( - "Error occurred while parsing file, while converting " + - "to a org.w3c.dom.Document : " + e.getMessage(), e); - } - } - - private static String getPropertyValue(Device device, String property) { - for (Device.Property prop : device.getProperties()) { - if (property.equals(prop.getName())) { - return prop.getValue(); - } - } - return null; - } - - private 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 MobileDevice convertToMobileDevice(Device device) { - MobileDevice mobileDevice = null; - if (device != null) { - mobileDevice = new MobileDevice(); - mobileDevice.setMobileDeviceId(device.getDeviceIdentifier()); - mobileDevice.setImei(getPropertyValue(device, MOBILE_DEVICE_IMEI)); - mobileDevice.setImsi(getPropertyValue(device, MOBILE_DEVICE_IMSI)); - mobileDevice.setModel(getPropertyValue(device, MOBILE_DEVICE_MODEL)); - mobileDevice.setOsVersion(getPropertyValue(device, MOBILE_DEVICE_OS_VERSION)); - mobileDevice.setVendor(getPropertyValue(device, MOBILE_DEVICE_VENDOR)); - mobileDevice.setLatitude(getPropertyValue(device, MOBILE_DEVICE_LATITUDE)); - mobileDevice.setLongitude(getPropertyValue(device, MOBILE_DEVICE_LONGITUDE)); - - if (device.getProperties() != null) { - Map deviceProperties = new HashMap(); - for (Device.Property deviceProperty : device.getProperties()) { - deviceProperties.put(deviceProperty.getName(), deviceProperty.getValue()); - } - - mobileDevice.setDeviceProperties(deviceProperties); - } else { - mobileDevice.setDeviceProperties(new HashMap()); - } - } - return mobileDevice; - } - - public static Device convertToDevice(MobileDevice mobileDevice) { - Device device = null; - if (mobileDevice != null) { - device = new Device(); - List propertyList = new ArrayList(); - propertyList.add(getProperty(MOBILE_DEVICE_IMEI, mobileDevice.getImei())); - propertyList.add(getProperty(MOBILE_DEVICE_IMSI, mobileDevice.getImsi())); - propertyList.add(getProperty(MOBILE_DEVICE_MODEL, mobileDevice.getModel())); - propertyList.add(getProperty(MOBILE_DEVICE_OS_VERSION, mobileDevice.getOsVersion())); - propertyList.add(getProperty(MOBILE_DEVICE_VENDOR, mobileDevice.getVendor())); - if(mobileDevice.getLatitude() != null) { - propertyList.add(getProperty(MOBILE_DEVICE_LATITUDE, mobileDevice.getLatitude())); - } - if(mobileDevice.getLongitude() != null) { - propertyList.add(getProperty(MOBILE_DEVICE_LONGITUDE, mobileDevice.getLongitude())); - } - propertyList.add(getProperty(MOBILE_DEVICE_SERIAL, mobileDevice.getSerial())); - - if (mobileDevice.getDeviceProperties() != null) { - for (Map.Entry deviceProperty : mobileDevice.getDeviceProperties() - .entrySet()) { - propertyList - .add(getProperty(deviceProperty.getKey(), deviceProperty.getValue())); - } - } - - device.setProperties(propertyList); - device.setDeviceIdentifier(mobileDevice.getMobileDeviceId()); - } - return device; - } - - public static MobileOperation convertToMobileOperation(Operation operation) { - MobileOperation mobileOperation = new MobileOperation(); - MobileOperationProperty operationProperty; - List properties = new LinkedList(); - mobileOperation.setFeatureCode(operation.getCode()); - mobileOperation.setCreatedDate(new Date().getTime()); - Properties operationProperties = operation.getProperties(); - for (String key : operationProperties.stringPropertyNames()) { - operationProperty = new MobileOperationProperty(); - operationProperty.setProperty(key); - operationProperty.setValue(operationProperties.getProperty(key)); - properties.add(operationProperty); - } - mobileOperation.setProperties(properties); - return mobileOperation; - } - - public static List getMobileOperationIdsFromMobileDeviceOperations( - List mobileDeviceOperationMappings) { - List mobileOperationIds = new ArrayList(mobileDeviceOperationMappings.size()); - for (MobileDeviceOperationMapping mobileDeviceOperationMapping : mobileDeviceOperationMappings) { - mobileOperationIds.add(mobileDeviceOperationMapping.getOperationId()); - } - return mobileOperationIds; - } - - public static Operation convertMobileOperationToOperation(MobileOperation mobileOperation) { - Operation operation = new Operation(); - Properties properties = new Properties(); - operation.setCode(mobileOperation.getFeatureCode()); - for (MobileOperationProperty mobileOperationProperty : mobileOperation.getProperties()) { - properties - .put(mobileOperationProperty.getProperty(), mobileOperationProperty.getValue()); - } - operation.setProperties(properties); - return operation; - } - - public static MobileFeature convertToMobileFeature(Feature feature) { - MobileFeature mobileFeature = new MobileFeature(); - mobileFeature.setName(feature.getName()); - mobileFeature.setCode(feature.getCode()); - mobileFeature.setDescription(feature.getDescription()); - mobileFeature.setDeviceType(feature.getDeviceType()); - return mobileFeature; - } - - public static Feature convertToFeature(MobileFeature mobileFeature) { - Feature feature = new Feature(); - feature.setDescription(mobileFeature.getDescription()); - feature.setDeviceType(mobileFeature.getDeviceType()); - feature.setCode(mobileFeature.getCode()); - feature.setName(mobileFeature.getName()); - return feature; - } - - public static Registry getConfigurationRegistry() throws MobileDeviceMgtPluginException { - try { - int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); - return MobileDeviceManagementDataHolder.getInstance().getRegistryService() - .getConfigSystemRegistry( - tenantId); - } catch (RegistryException e) { - throw new MobileDeviceMgtPluginException( - "Error in retrieving conf registry instance: " + - e.getMessage(), e); - } - } - - public static Resource getRegistryResource(String path) throws MobileDeviceMgtPluginException { - try { - if(MobileDeviceManagementUtil.getConfigurationRegistry().resourceExists(path)){ - return MobileDeviceManagementUtil.getConfigurationRegistry().get(path); - } - return null; - } catch (RegistryException e) { - throw new MobileDeviceMgtPluginException("Error in retrieving registry resource : " + - e.getMessage(), e); - } - } - - public static boolean putRegistryResource(String path, - Resource resource) - throws MobileDeviceMgtPluginException { - boolean status; - try { - MobileDeviceManagementUtil.getConfigurationRegistry().beginTransaction(); - MobileDeviceManagementUtil.getConfigurationRegistry().put(path, resource); - MobileDeviceManagementUtil.getConfigurationRegistry().commitTransaction(); - status = true; - } catch (RegistryException e) { - throw new MobileDeviceMgtPluginException( - "Error occurred while persisting registry resource : " + - e.getMessage(), e); - } - return status; - } - - public static String getResourcePath(String resourceName, String platform) { - String regPath = ""; - switch (platform) { - case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID: - regPath = MobilePluginConstants.MOBILE_CONFIG_REGISTRY_ROOT + "/" + - DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID + - "/" + resourceName; - break; - case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS: - regPath = MobilePluginConstants.MOBILE_CONFIG_REGISTRY_ROOT + "/" + - DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS + - "/" + resourceName; - break; - case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS: - regPath = MobilePluginConstants.MOBILE_CONFIG_REGISTRY_ROOT + "/" + - DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS + - "/" + resourceName; - break; - } - return regPath; - } - - public static String getPlatformConfigPath(String platform) { - String regPath = ""; - switch (platform) { - case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID: - regPath = DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID; - break; - case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS: - regPath = DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_WINDOWS; - break; - case DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS: - regPath = DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_IOS; - break; - } - return regPath; - } - - public static boolean createRegistryCollection(String path) - throws MobileDeviceMgtPluginException { - try { - if (! MobileDeviceManagementUtil.getConfigurationRegistry().resourceExists(path)) { - Resource resource = MobileDeviceManagementUtil.getConfigurationRegistry().newCollection(); - MobileDeviceManagementUtil.getConfigurationRegistry().beginTransaction(); - MobileDeviceManagementUtil.getConfigurationRegistry().put(path, resource); - MobileDeviceManagementUtil.getConfigurationRegistry().commitTransaction(); - } - return true; - } catch (MobileDeviceMgtPluginException e) { - throw new MobileDeviceMgtPluginException( - "Error occurred while creating a registry collection : " + - e.getMessage(), e); - } catch (RegistryException e) { - throw new MobileDeviceMgtPluginException( - "Error occurred while creating a registry collection : " + - e.getMessage(), e); - } - } - - public static List getMissingFeatures(List supportedFeatures, List existingFeatures) { - HashMap featureHashMap = new HashMap(); - for (Feature feature: existingFeatures) { - featureHashMap.put(feature.getCode(),feature); - } - List missingFeatures = new ArrayList(); - for (Feature supportedFeature : supportedFeatures) { - if (featureHashMap.get(supportedFeature.getCode()) != null) { - continue; - } - missingFeatures.add(supportedFeature); - } - return missingFeatures; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java deleted file mode 100644 index 461de8a1a..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/MobileDeviceManagementConfigTests.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceManagementConfig; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import javax.xml.XMLConstants; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import java.io.File; - -/** - * Class for holding unit-tests related to MobileDeviceManagementConfig class. - */ - -public class MobileDeviceManagementConfigTests { - - private static final Log log = LogFactory.getLog(MobileDeviceManagementConfigTests.class); - private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_MGT_REPOSITORY = - "./src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml"; - private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_DS_CONFIG = - "./src/test/resources/config/malformed-mobile-config-no-ds-config.xml"; - private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_JNDI_CONFIG = - "./src/test/resources/config/malformed-mobile-config-no-jndi-config.xml"; - private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_APIS_CONFIG = - "./src/test/resources/config/malformed-mobile-config-no-apis-config.xml"; - private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_API_CONFIG = - "./src/test/resources/config/malformed-mobile-config-no-api-config.xml"; - private static final String MALFORMED_TEST_CONFIG_LOCATION_NO_API_PUBLISHER_CONFIG = - "./src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml"; - private static final String TEST_CONFIG_SCHEMA_LOCATION = - "./src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd"; - - private Schema schema; - - @BeforeClass - private void initSchema() { - File deviceManagementSchemaConfig = - new File(MobileDeviceManagementConfigTests.TEST_CONFIG_SCHEMA_LOCATION); - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - try { - schema = factory.newSchema(deviceManagementSchemaConfig); - } catch (SAXException e) { - Assert.fail("Invalid schema found", e); - } - } - - @Test - public void testMandateManagementRepositoryElement() { - File malformedConfig = - new File( - MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_MGT_REPOSITORY); - this.validateMalformedConfig(malformedConfig); - } - - @Test - public void testMandateDataSourceConfigurationElement() { - File malformedConfig = new File( - MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_DS_CONFIG); - this.validateMalformedConfig(malformedConfig); - } - - @Test - public void testMandateJndiLookupDefinitionElement() { - File malformedConfig = new File( - MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_JNDI_CONFIG); - this.validateMalformedConfig(malformedConfig); - } - - @Test - public void testMandateAPIPublisherElement() { - File malformedConfig = new File( - MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_API_PUBLISHER_CONFIG); - this.validateMalformedConfig(malformedConfig); - } - - @Test - public void testMandateAPIsElement() { - File malformedConfig = new File( - MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_APIS_CONFIG); - this.validateMalformedConfig(malformedConfig); - } - - @Test - public void testMandateAPIElement() { - File malformedConfig = new File( - MobileDeviceManagementConfigTests.MALFORMED_TEST_CONFIG_LOCATION_NO_API_CONFIG); - this.validateMalformedConfig(malformedConfig); - } - - /** - * Validates a given malformed-configuration file. - */ - private void validateMalformedConfig(File malformedConfig) { - try { - JAXBContext ctx = JAXBContext.newInstance(MobileDeviceManagementConfig.class); - Unmarshaller um = ctx.createUnmarshaller(); - um.setSchema(this.getSchema()); - um.unmarshal(malformedConfig); - Assert.assertTrue(false); - } catch (JAXBException e) { - Throwable linkedException = e.getLinkedException(); - if (!(linkedException instanceof SAXParseException)) { - log.error("Unexpected error occurred while unmarshalling mobile device management config", e); - Assert.assertTrue(false); - } - Assert.assertTrue(true); - } - } - - private Schema getSchema() { - return schema; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java deleted file mode 100644 index fa263f384..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/DBTypes.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.common; - - -public enum DBTypes { - Oracle("Oracle"),H2("H2"),MySql("MySql"); - - String dbName ; - DBTypes(String dbStrName) { - dbName = dbStrName; - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java deleted file mode 100644 index 042e105bf..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfiguration.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.common; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement(name = "Type") -public class TestDBConfiguration { - - private String connectionURL; - private String driverClassName; - private String username; - private String password; - - @Override public String toString() { - return "TestDataSourceConfiguration{" + - "ConnectionURL='" + connectionURL + '\'' + - ", DriverClassName='" + driverClassName + '\'' + - ", Username='" + username + '\'' + - ", Password='" + password + '\'' + - ", Type='" + dbType + '\'' + - '}'; - } - - private String dbType; - - @XmlElement(name = "ConnectionURL", nillable = false) - public String getConnectionURL() { - return connectionURL; - } - - public void setConnectionURL(String connectionURL) { - this.connectionURL = connectionURL; - } - - @XmlElement(name = "DriverClassName", nillable = false) - public String getDriverClassName() { - return driverClassName; - } - - public void setDriverClassName(String driverClassName) { - this.driverClassName = driverClassName; - } - - @XmlElement(name = "Username", nillable = false) - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - @XmlElement(name = "Password", nillable = false) - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @XmlAttribute(name = "name") - public String getType() { - return dbType; - } - - public void setType(String type) { - this.dbType = type; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java deleted file mode 100644 index 88092ea41..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/common/TestDBConfigurations.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.common; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.util.List; - -@XmlRootElement(name = "TestDataSourceConfigurations") -public class TestDBConfigurations { - - private List dbTypesList; - - @XmlElement(name = "Type") - public List getDbTypesList() { - return dbTypesList; - } - - public void setDbTypesList(List dbTypesList) { - this.dbTypesList = dbTypesList; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java deleted file mode 100644 index f454f6f06..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/java/org/wso2/carbon/device/mgt/mobile/impl/dao/util/MobileDatabaseUtils.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.impl.dao.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Document; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.mobile.dao.MobileDeviceManagementDAOException; -import org.wso2.carbon.device.mgt.mobile.impl.common.DBTypes; -import org.wso2.carbon.device.mgt.mobile.impl.common.TestDBConfiguration; -import org.wso2.carbon.device.mgt.mobile.impl.common.TestDBConfigurations; -import org.wso2.carbon.device.mgt.mobile.util.MobileDeviceManagementUtil; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import java.io.File; -import java.sql.*; - -/** - * This class provides the utility methods needed for DAO related test executions. - */ -public class MobileDatabaseUtils { - - private static final Log log = LogFactory.getLog(MobileDatabaseUtils.class); - public static final String TEST_RESOURCES_DB_CONFIG_FILE = - "src/test/resources/testdbconfig.xml"; - - public static void cleanupResources(Connection conn, Statement 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 TestDBConfiguration getTestDBConfiguration(DBTypes dbType) throws - MobileDeviceManagementDAOException, - DeviceManagementException { - File deviceMgtConfig = new File(TEST_RESOURCES_DB_CONFIG_FILE); - Document doc; - TestDBConfiguration testDBConfiguration = null; - TestDBConfigurations testDBConfigurations; - - doc = MobileDeviceManagementUtil.convertToDocument(deviceMgtConfig); - JAXBContext testDBContext; - - try { - testDBContext = JAXBContext.newInstance(TestDBConfigurations.class); - Unmarshaller unmarshaller = testDBContext.createUnmarshaller(); - testDBConfigurations = (TestDBConfigurations) unmarshaller.unmarshal(doc); - } catch (JAXBException e) { - throw new MobileDeviceManagementDAOException("Error parsing test db configurations", e); - } - - for (TestDBConfiguration testDBConfiguration1 : testDBConfigurations.getDbTypesList()) { - testDBConfiguration = testDBConfiguration1; - if (testDBConfiguration.getType().equals(dbType.toString())) { - break; - } - } - - return testDBConfiguration; - } - - public static void createH2DB(TestDBConfiguration testDBConf) throws Exception { - Connection conn = null; - Statement stmt = null; - try { - Class.forName(testDBConf.getDriverClassName()); - conn = DriverManager.getConnection(testDBConf.getConnectionURL()); - stmt = conn.createStatement(); - stmt.executeUpdate("RUNSCRIPT FROM './src/test/resources/sql/h2.sql'"); - } finally { - cleanupResources(conn, stmt, null); - } - } -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-config.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-config.xml deleted file mode 100644 index 3fad2eceb..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-config.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - jdbc/MobileIOSDM_DS - - - - - jdbc/MobileAndroidDM_DS - - - - - jdbc/MobileWindowsDM_DS - - - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml deleted file mode 100644 index 94fb50462..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-api-publisher-config.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - jdbc/MobileDM_DS - - - - - - - - enrollment - admin - enrollment - 1.0.0 - http://localhost:9763/ - http,https - - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-apis-config.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-apis-config.xml deleted file mode 100644 index 743fe6c24..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-apis-config.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - jdbc/MobileDM_DS - - - - - - - - enrollment - admin - enrollment - 1.0.0 - http://localhost:9763/ - http,https - - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-ds-config.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-ds-config.xml deleted file mode 100644 index 1f1b5ef14..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-ds-config.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - jdbc/MobileDM_DS - - - - - - - - enrollment - admin - enrollment - 1.0.0 - http://localhost:9763/ - http,https - - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml deleted file mode 100644 index 06dc33761..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-jndi-config.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - jdbc/MobileDM_DS - - - - - - - - enrollment - admin - enrollment - 1.0.0 - http://localhost:9763/ - http,https - - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml deleted file mode 100644 index 617742635..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/malformed-mobile-config-no-mgt-repo.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - jdbc/MobileDM_DS - - - - - - - - enrollment - admin - enrollment - 1.0.0 - http://localhost:9763/ - http,https - - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd deleted file mode 100644 index ff6435e50..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/config/schema/MobileDeviceManagementConfigSchema.xsd +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/log4j.properties b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/log4j.properties deleted file mode 100644 index 675d63149..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/log4j.properties +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright 2015 WSO2, Inc. (http://wso2.com) -# -# 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. -# - -# -# This is the log4j configuration file used by WSO2 Carbon -# -# IMPORTANT : Please do not remove or change the names of any -# of the Appenders defined here. The layout pattern & log file -# can be changed using the WSO2 Carbon Management Console, and those -# settings will override the settings in this file. -# - -log4j.rootLogger=DEBUG, STD_OUT - -# Redirect log messages to console -log4j.appender.STD_OUT=org.apache.log4j.ConsoleAppender -log4j.appender.STD_OUT.Target=System.out -log4j.appender.STD_OUT.layout=org.apache.log4j.PatternLayout -log4j.appender.STD_OUT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/sql/h2.sql b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/sql/h2.sql deleted file mode 100644 index 78b5b7b8b..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/sql/h2.sql +++ /dev/null @@ -1,54 +0,0 @@ - --- ----------------------------------------------------- --- Table `AD_DEVICE` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `AD_DEVICE` ( - `DEVICE_ID` VARCHAR(45) NOT NULL , - `PUSH_TOKEN` VARCHAR(45) NULL DEFAULT NULL , - `IMEI` VARCHAR(45) NULL DEFAULT NULL , - `IMSI` VARCHAR(45) NULL DEFAULT NULL , - `OS_VERSION` VARCHAR(45) NULL DEFAULT NULL , - `DEVICE_MODEL` VARCHAR(45) NULL DEFAULT NULL , - `VENDOR` VARCHAR(45) NULL DEFAULT NULL , - `LATITUDE` VARCHAR(45) NULL DEFAULT NULL, - `LONGITUDE` VARCHAR(45) NULL DEFAULT NULL, - `CHALLENGE` VARCHAR(45) NULL DEFAULT NULL, - `TOKEN` VARCHAR(500) NULL DEFAULT NULL, - `UNLOCK_TOKEN` VARCHAR(500) NULL DEFAULT NULL, - `SERIAL` VARCHAR(45) NULL DEFAULT NULL, - PRIMARY KEY (`DEVICE_ID`) ); - - --- ----------------------------------------------------- --- Table `AD_FEATURE` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `AD_FEATURE` ( - `ID` INT NOT NULL AUTO_INCREMENT , - `CODE` VARCHAR(45) NOT NULL, - `NAME` VARCHAR(100) NULL , - `DESCRIPTION` VARCHAR(200) NULL , - `DEVICE_TYPE` VARCHAR(50) NULL , - PRIMARY KEY (`ID`) ); - --- ----------------------------------------------------- --- Table `AD_OPERATION` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `AD_OPERATION` ( - `OPERATION_ID` INT NOT NULL AUTO_INCREMENT , - `FEATURE_CODE` VARCHAR(45) NOT NULL , - `CREATED_DATE` BIGINT NULL , - PRIMARY KEY (`OPERATION_ID`)); - - --- ----------------------------------------------------- --- Table `AD_FEATURE_PROPERTY` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `AD_FEATURE_PROPERTY` ( - `PROPERTY` VARCHAR(45) NOT NULL , - `FEATURE_ID` INT NOT NULL , - PRIMARY KEY (`PROPERTY`) , - CONSTRAINT `fk_AD_FEATURE_PROPERTY_AD_FEATURE1` - FOREIGN KEY (`FEATURE_ID` ) - REFERENCES `AD_FEATURE` (`ID` ) - ON DELETE NO ACTION - ON UPDATE NO ACTION); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testdbconfig.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testdbconfig.xml deleted file mode 100644 index eee04a324..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testdbconfig.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - jdbc:h2:mem:cdm-mobile-test-db;DB_CLOSE_DELAY=-1 - org.h2.Driver - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testng.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testng.xml deleted file mode 100644 index f73ab880b..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/test/resources/testng.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml deleted file mode 100644 index e19a3f965..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - device-mgt - org.wso2.carbon.devicemgt-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.mobile.url.printer - 2.1.0-SNAPSHOT - bundle - WSO2 Carbon - Startup Handler That Prints MDM End-User Web-App URL - WSO2 Carbon - Startup Handler That Prints MDM End-User Web-App URL - http://wso2.org - - - - - org.apache.felix - maven-scr-plugin - - - org.apache.felix - maven-bundle-plugin - 1.4.0 - true - - - ${project.artifactId} - ${project.artifactId} - ${carbon.mobile.device.mgt.version} - Bundle Containing The Startup Handler That Prints MDM End-User Web-App URL - org.wso2.carbon.device.mgt.mobile.url.printer.internal - - org.osgi.framework, - org.osgi.service.component, - org.apache.commons.logging, - org.apache.axis2.*;version="${axis2.osgi.version.range}", - org.wso2.carbon.core, - org.wso2.carbon.utils.*, - - - !org.wso2.carbon.device.mgt.mobile.url.printer.internal, - org.wso2.carbon.device.mgt.mobile.url.printer, - - - - - - - - - - org.eclipse.osgi - org.eclipse.osgi - - - org.eclipse.osgi - org.eclipse.osgi.services - - - org.wso2.carbon - org.wso2.carbon.core - - - org.wso2.carbon - org.wso2.carbon.logging - - - org.wso2.carbon - org.wso2.carbon.utils - - - org.apache.axis2.wso2 - axis2 - - - - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java deleted file mode 100644 index 80aa39805..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.url.printer; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.core.ServerStartupObserver; -import org.wso2.carbon.device.mgt.mobile.url.printer.internal.URLPrinterDataHolder; -import org.wso2.carbon.utils.CarbonUtils; -import org.wso2.carbon.utils.ConfigurationContextService; -import org.wso2.carbon.utils.NetworkUtils; - -public class URLPrinterStartupHandler implements ServerStartupObserver { - - private static final Log log = LogFactory.getLog(URLPrinterStartupHandler.class); - - @Override - public void completingServerStartup() { - - } - - @Override - public void completedServerStartup() { - log.info("EMM Console URL : " + this.getEmmUrl()); - } - - private String getEmmUrl() { - // Hostname - String hostName = "localhost"; - try { - hostName = NetworkUtils.getMgtHostName(); - } catch (Exception ignored) { - } - // HTTPS port - String mgtConsoleTransport = CarbonUtils.getManagementTransport(); - ConfigurationContextService configContextService = - URLPrinterDataHolder.getInstance().getConfigurationContextService(); - int port = CarbonUtils.getTransportPort(configContextService, mgtConsoleTransport); - int httpsProxyPort = - CarbonUtils.getTransportProxyPort(configContextService.getServerConfigContext(), - mgtConsoleTransport); - if (httpsProxyPort > 0) { - port = httpsProxyPort; - } - return "https://" + hostName + ":" + port + "/emm"; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java deleted file mode 100644 index 0dd8a459d..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterDataHolder.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.url.printer.internal; - -import org.wso2.carbon.utils.ConfigurationContextService; - -public class URLPrinterDataHolder { - - private ConfigurationContextService configurationContextService; - private static URLPrinterDataHolder thisInstance = new URLPrinterDataHolder(); - - private URLPrinterDataHolder() {} - - public static URLPrinterDataHolder getInstance() { - return thisInstance; - } - - public ConfigurationContextService getConfigurationContextService() { - return configurationContextService; - } - - public void setConfigurationContextService(ConfigurationContextService configurationContextService) { - this.configurationContextService = configurationContextService; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java b/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java deleted file mode 100644 index 88a2b2dae..000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/internal/URLPrinterStartupHandlerServiceComponent.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.mobile.url.printer.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.osgi.framework.BundleContext; -import org.osgi.service.component.ComponentContext; -import org.wso2.carbon.core.ServerStartupObserver; -import org.wso2.carbon.device.mgt.mobile.url.printer.URLPrinterStartupHandler; -import org.wso2.carbon.utils.ConfigurationContextService; - -/** - * @scr.component name="org.wso2.carbon.device.mgt.mobile.url.printer.URLPrinterStartupHandlerServiceComponent" - * immediate="true" - * @scr.reference name="config.context.service" - * interface="org.wso2.carbon.utils.ConfigurationContextService" - * cardinality="0..1" - * policy="dynamic" - * bind="setConfigurationContextService" - * unbind="unsetConfigurationContextService" - */ -public class URLPrinterStartupHandlerServiceComponent { - - private static final Log log = LogFactory.getLog(URLPrinterStartupHandlerServiceComponent.class); - - @SuppressWarnings("unused") - protected void activate(ComponentContext componentContext) { - try { - BundleContext bundleContext = componentContext.getBundleContext(); - /* Registering URL printer start-up handler */ - bundleContext.registerService(ServerStartupObserver.class, new URLPrinterStartupHandler(), null); - } catch (Throwable e) { - log.error("Error occurred while activating URL printer server start-up handler service component", e); - } - } - - @SuppressWarnings("unused") - protected void deactivate(ComponentContext componentContext) { - //do nothing - } - - protected void setConfigurationContextService(ConfigurationContextService configurationContextService) { - if (log.isDebugEnabled()) { - log.debug("Setting ConfigurationContextService"); - } - URLPrinterDataHolder.getInstance().setConfigurationContextService(configurationContextService); - } - - protected void unsetConfigurationContextService(ConfigurationContextService configurationContextService) { - if (log.isDebugEnabled()) { - log.debug("Un-setting ConfigurationContextService"); - } - URLPrinterDataHolder.getInstance().setConfigurationContextService(null); - } - -} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java index 1eaad8ad4..80aa39805 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.url.printer/src/main/java/org/wso2/carbon/device/mgt/mobile/url/printer/URLPrinterStartupHandler.java @@ -37,7 +37,7 @@ public class URLPrinterStartupHandler implements ServerStartupObserver { @Override public void completedServerStartup() { - log.info("Device Management Console URL : " + this.getEmmUrl()); + log.info("EMM Console URL : " + this.getEmmUrl()); } private String getEmmUrl() { @@ -58,7 +58,7 @@ public class URLPrinterStartupHandler implements ServerStartupObserver { if (httpsProxyPort > 0) { port = httpsProxyPort; } - return "https://" + hostName + ":" + port + "/devicemgt"; + return "https://" + hostName + ":" + port + "/emm"; } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManagementService.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManagementService.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManagementService.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManagementService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManager.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManager.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManager.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidDeviceManager.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidFeatureManager.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidPolicyMonitoringService.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidPolicyMonitoringService.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidPolicyMonitoringService.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/AndroidPolicyMonitoringService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidDAOFactory.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidDAOFactory.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidDAOFactory.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidDAOFactory.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidFeatureManagementDAOException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidFeatureManagementDAOException.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidFeatureManagementDAOException.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/AndroidFeatureManagementDAOException.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidDeviceDAOImpl.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidDeviceDAOImpl.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidDeviceDAOImpl.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidDeviceDAOImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidFeatureDAOImpl.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidFeatureDAOImpl.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidFeatureDAOImpl.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/dao/impl/AndroidFeatureDAOImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMResult.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/gcm/GCMUtil.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginConstants.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginConstants.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginConstants.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginConstants.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginUtils.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginUtils.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidPluginUtils.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidUtils.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidUtils.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/android/util/AndroidUtils.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManagementService.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManagementService.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManagementService.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManagementService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManager.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManager.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManager.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsDeviceManager.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsFeatureManager.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsFeatureManager.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsFeatureManager.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsFeatureManager.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsPolicyMonitoringService.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsPolicyMonitoringService.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsPolicyMonitoringService.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/WindowsPolicyMonitoringService.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsDAOFactory.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsDAOFactory.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsDAOFactory.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsDAOFactory.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsFeatureManagementDAOException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsFeatureManagementDAOException.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsFeatureManagementDAOException.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/WindowsFeatureManagementDAOException.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsDeviceDAOImpl.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsDeviceDAOImpl.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsDeviceDAOImpl.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsDeviceDAOImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsFeatureDAOImpl.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsFeatureDAOImpl.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsFeatureDAOImpl.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/dao/impl/WindowsFeatureDAOImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginConstants.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginConstants.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginConstants.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginConstants.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginUtils.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginUtils.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsPluginUtils.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsUtils.java similarity index 100% rename from components/device-mgt/org.wso2.carbon.device.mgt.mobile.impl/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsUtils.java rename to components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/impl/windows/util/WindowsUtils.java diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java index d8943def1..869904e81 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementDataHolder.java @@ -19,6 +19,7 @@ package org.wso2.carbon.device.mgt.mobile.internal; import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.impl.android.gcm.GCMService; import org.wso2.carbon.registry.core.service.RegistryService; /** @@ -27,6 +28,8 @@ import org.wso2.carbon.registry.core.service.RegistryService; public class MobileDeviceManagementDataHolder { private RegistryService registryService; + private DeviceManagementService androidDeviceManagementService; + private GCMService gcmService; private static MobileDeviceManagementDataHolder thisInstance = new MobileDeviceManagementDataHolder(); @@ -45,4 +48,20 @@ public class MobileDeviceManagementDataHolder { this.registryService = registryService; } + public DeviceManagementService getAndroidDeviceManagementService() { + return androidDeviceManagementService; + } + + public void setAndroidDeviceManagementService( + DeviceManagementService androidDeviceManagementService) { + this.androidDeviceManagementService = androidDeviceManagementService; + } + + public GCMService getGCMService() { + return gcmService; + } + + public void setGCMService(GCMService gcmService) { + this.gcmService = gcmService; + } } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java index e08771b3b..92404b67a 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile/src/main/java/org/wso2/carbon/device/mgt/mobile/internal/MobileDeviceManagementServiceComponent.java @@ -23,13 +23,20 @@ import org.apache.commons.logging.LogFactory; 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; import org.wso2.carbon.device.mgt.mobile.common.MobileDeviceMgtPluginException; import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceConfigurationManager; import org.wso2.carbon.device.mgt.mobile.config.MobileDeviceManagementConfig; import org.wso2.carbon.device.mgt.mobile.config.datasource.MobileDataSourceConfig; import org.wso2.carbon.device.mgt.mobile.dao.AbstractMobileDeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.mobile.dao.util.MobileDeviceManagementDAOUtil; +import org.wso2.carbon.device.mgt.mobile.impl.android.AndroidDeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.impl.android.AndroidPolicyMonitoringService; +import org.wso2.carbon.device.mgt.mobile.impl.android.gcm.GCMService; +import org.wso2.carbon.device.mgt.mobile.impl.windows.WindowsDeviceManagementService; +import org.wso2.carbon.device.mgt.mobile.impl.windows.WindowsPolicyMonitoringService; import org.wso2.carbon.ndatasource.core.DataSourceService; +import org.wso2.carbon.policy.mgt.common.spi.PolicyMonitoringService; import org.wso2.carbon.registry.core.service.RegistryService; import java.util.Map; @@ -53,6 +60,10 @@ import java.util.Map; */ public class MobileDeviceManagementServiceComponent { + private ServiceRegistration androidServiceRegRef; + private ServiceRegistration windowsServiceRegRef; + private ServiceRegistration gcmServiceRegRef; + private static final Log log = LogFactory.getLog(MobileDeviceManagementServiceComponent.class); protected void activate(ComponentContext ctx) { @@ -89,6 +100,30 @@ public class MobileDeviceManagementServiceComponent { log.error("Exception occurred while initializing mobile device management database schema", e); } } + DeviceManagementService androidDeviceManagementService = new AndroidDeviceManagementService(); + GCMService gcmService = new GCMService(); + + androidServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + androidDeviceManagementService, null); + windowsServiceRegRef = + bundleContext.registerService(DeviceManagementService.class.getName(), + new WindowsDeviceManagementService(), null); + + gcmServiceRegRef = + bundleContext.registerService(GCMService.class.getName(), gcmService, null); + + + // Policy management service + + bundleContext.registerService(PolicyMonitoringService.class, + new AndroidPolicyMonitoringService(), null); + bundleContext.registerService(PolicyMonitoringService.class, + new WindowsPolicyMonitoringService(), null); + + MobileDeviceManagementDataHolder.getInstance().setAndroidDeviceManagementService( + androidDeviceManagementService); + MobileDeviceManagementDataHolder.getInstance().setGCMService(gcmService); if (log.isDebugEnabled()) { log.debug("Mobile Device Management Service Component has been successfully activated"); } @@ -102,6 +137,15 @@ public class MobileDeviceManagementServiceComponent { log.debug("De-activating Mobile Device Management Service Component"); } try { + if (androidServiceRegRef != null) { + androidServiceRegRef.unregister(); + } + if (windowsServiceRegRef != null) { + windowsServiceRegRef.unregister(); + } + if (gcmServiceRegRef != null) { + gcmServiceRegRef.unregister(); + } if (log.isDebugEnabled()) { log.debug( "Mobile Device Management Service Component has been successfully de-activated"); diff --git a/components/mobile-plugins/mobile-base-plugin/pom.xml b/components/mobile-plugins/mobile-base-plugin/pom.xml index b2912b562..94ae0d56a 100644 --- a/components/mobile-plugins/mobile-base-plugin/pom.xml +++ b/components/mobile-plugins/mobile-base-plugin/pom.xml @@ -34,8 +34,8 @@ org.wso2.carbon.device.mgt.mobile - org.wso2.carbon.device.mgt.mobile.api - org.wso2.carbon.device.mgt.mobile.ui + + org.wso2.carbon.device.mgt.mobile.url.printer diff --git a/components/mobile-plugins/pom.xml b/components/mobile-plugins/pom.xml index 7c62f920b..898aded05 100644 --- a/components/mobile-plugins/pom.xml +++ b/components/mobile-plugins/pom.xml @@ -27,15 +27,14 @@ 4.0.0 - org.wso2.carbon.devicemgt-plugins mobile-plugins pom WSO2 Carbon - Mobile Plugins http://wso2.org - android-plugin - windows-plugin + + mobile-base-plugin diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml similarity index 96% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml index 6e07d9f97..26b491a65 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/pom.xml +++ b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.devicemgt-plugins - device-mgt-feature + mobile-base-plugin-feature 2.1.0-SNAPSHOT ../pom.xml @@ -38,7 +38,7 @@ org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.mobile.impl + org.wso2.carbon.device.mgt.mobile org.wso2.carbon.devicemgt @@ -104,7 +104,7 @@ org.wso2.carbon.device.mgt.mobile - ../../../features/etc/feature.properties + ../../../../features/etc/feature.properties org.wso2.carbon.p2.category.type:server diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/build.properties b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/build.properties similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/build.properties rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/build.properties diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/conf/mobile-config.xml b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/conf/mobile-config.xml similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/conf/mobile-config.xml rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/conf/mobile-config.xml diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/h2.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/h2.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/h2.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/h2.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mssql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mssql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mssql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mssql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mysql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mysql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mysql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/mysql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/oracle.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/oracle.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/oracle.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/oracle.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/postgresql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/postgresql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/postgresql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/android/postgresql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/h2.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/h2.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/h2.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/h2.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mssql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mssql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mssql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mssql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mysql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mysql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mysql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/mysql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/oracle.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/oracle.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/oracle.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/oracle.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/postgresql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/postgresql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/postgresql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/ios/postgresql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/h2.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/h2.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/h2.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/h2.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mssql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mssql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mssql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mssql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mysql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mysql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mysql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/mysql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/oracle.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/oracle.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/oracle.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/oracle.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/postgresql.sql b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/postgresql.sql similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/postgresql.sql rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/dbscripts/plugins/windows/postgresql.sql diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf similarity index 100% rename from features/device-mgt/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf rename to features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf diff --git a/components/device-mgt/pom.xml b/features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml similarity index 53% rename from components/device-mgt/pom.xml rename to features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml index 78a844e8d..8b0d196e5 100644 --- a/components/device-mgt/pom.xml +++ b/features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml @@ -21,41 +21,20 @@ org.wso2.carbon.devicemgt-plugins - carbon-device-mgt-plugins-parent + mobile-plugins-feature 2.1.0-SNAPSHOT - ../../pom.xml + ../pom.xml 4.0.0 - org.wso2.carbon.devicemgt-plugins - device-mgt + mobile-base-plugin-feature 2.1.0-SNAPSHOT pom - WSO2 Carbon - Mobile Device Management Component + WSO2 Carbon - Device Management Feature http://wso2.org - org.wso2.carbon.device.mgt.mobile.impl - org.wso2.carbon.device.mgt.mobile.url.printer + org.wso2.carbon.device.mgt.mobile.feature - - - - - org.apache.felix - maven-scr-plugin - 1.7.2 - - - generate-scr-scrdescriptor - - scr - - - - - - - diff --git a/features/device-mgt/pom.xml b/features/mobile-plugins-feature/pom.xml similarity index 89% rename from features/device-mgt/pom.xml rename to features/mobile-plugins-feature/pom.xml index bebd11623..852a9f91e 100644 --- a/features/device-mgt/pom.xml +++ b/features/mobile-plugins-feature/pom.xml @@ -27,15 +27,14 @@ 4.0.0 - org.wso2.carbon.devicemgt-plugins - device-mgt-feature + mobile-plugins-feature 2.1.0-SNAPSHOT pom WSO2 Carbon - Device Management Feature http://wso2.org - org.wso2.carbon.device.mgt.mobile.feature + mobile-base-plugin-feature diff --git a/pom.xml b/pom.xml index 0848df962..318c7e3df 100644 --- a/pom.xml +++ b/pom.xml @@ -37,10 +37,9 @@ - components/device-mgt - + components/mobile-plugins - features/device-mgt + features/mobile-plugins-feature From 887af1a9f6b3fb49d75c6a0031747f5437a73325 Mon Sep 17 00:00:00 2001 From: charithag Date: Tue, 29 Mar 2016 14:22:48 +0530 Subject: [PATCH 06/10] Enable IoT base plugin component back and fix isses --- .../pom.xml | 261 ---------------- .../pom.xml | 261 ---------------- .../pom.xml | 123 -------- .../plugin/constants/CameraConstants.java | 27 -- .../iot/camera/plugin/impl/CameraManager.java | 281 ------------------ .../plugin/impl/CameraManagerService.java | 112 ------- .../iot/camera/plugin/impl/dao/CameraDAO.java | 121 -------- .../impl/dao/impl/CameraDeviceDAOImpl.java | 237 --------------- .../impl/util/VirtualFireAlarmUtils.java | 45 --- .../CameraManagementServiceComponent.java | 98 ------ .../pom.xml | 62 ---- components/iot-plugins/camera-plugin/pom.xml | 63 ---- .../mgt/iot/api/DevicesManagerService.java | 115 ++----- .../mgt/iot/api/GroupManagerService.java | 20 +- .../mgt/iot/api/StatsManagerService.java | 103 ------- .../src/main/webapp/WEB-INF/cxf-servlet.xml | 20 -- .../org.wso2.carbon.device.mgt.iot/pom.xml | 16 +- components/iot-plugins/pom.xml | 14 +- pom.xml | 6 +- 19 files changed, 56 insertions(+), 1929 deletions(-) delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java delete mode 100644 components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml delete mode 100644 components/iot-plugins/camera-plugin/pom.xml delete mode 100644 components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml deleted file mode 100644 index b1930e8f0..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.controller.service.impl/pom.xml +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - camera-plugin - org.wso2.carbon.devicemgt-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.device.mgt.iot.camera.controller.service.impl - war - WSO2 Carbon - IoT Server Camera API - WSO2 Carbon - Camera Service Controller API Implementation - http://wso2.org - - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.common - provided - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.core - provided - - - org.apache.axis2.wso2 - axis2-client - - - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.analytics - provided - - - org.apache.axis2.wso2 - axis2-client - - - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.certificate.mgt.core - provided - - - commons-codec.wso2 - commons-codec - - - - - - - - org.apache.cxf - cxf-rt-frontend-jaxws - provided - - - org.apache.cxf - cxf-rt-frontend-jaxrs - provided - - - org.apache.cxf - cxf-rt-transports-http - provided - - - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - provided - - - - - org.apache.httpcomponents - httpasyncclient - 4.1 - provided - - - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.iot - provided - - - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.iot.camera.plugin.impl - provided - - - - - org.codehaus.jackson - jackson-core-asl - - - org.codehaus.jackson - jackson-jaxrs - - - javax - javaee-web-api - provided - - - javax.ws.rs - jsr311-api - provided - - - commons-httpclient.wso2 - commons-httpclient - provided - - - - org.wso2.carbon - org.wso2.carbon.utils - provided - - - 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.wso2 - commons-codec - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.apimgt.annotations - provided - - - - org.igniterealtime.smack.wso2 - smack - provided - - - org.igniterealtime.smack.wso2 - smackx - provided - - - org.wso2.carbon.devicemgt - org.wso2.carbon.apimgt.webapp.publisher - provided - - - - - - - - - maven-compiler-plugin - - UTF-8 - ${wso2.maven.compiler.source} - ${wso2.maven.compiler.target} - - - - maven-war-plugin - - camera - - - - - - diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml deleted file mode 100644 index 98667f028..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.manager.service.impl/pom.xml +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - camera-plugin - org.wso2.carbon.devicemgt-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.device.mgt.iot.camera.manager.service.impl - war - WSO2 Carbon - IoT Server Camera API - WSO2 Carbon - Camera Service Management API Implementation - http://wso2.org - - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.common - provided - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.core - provided - - - org.apache.axis2.wso2 - axis2-client - - - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.device.mgt.analytics - provided - - - org.apache.axis2.wso2 - axis2-client - - - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.certificate.mgt.core - provided - - - commons-codec.wso2 - commons-codec - - - - - - - - org.apache.cxf - cxf-rt-frontend-jaxws - provided - - - org.apache.cxf - cxf-rt-frontend-jaxrs - provided - - - org.apache.cxf - cxf-rt-transports-http - provided - - - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - provided - - - - - org.apache.httpcomponents - httpasyncclient - 4.1 - provided - - - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.iot - provided - - - org.wso2.carbon.devicemgt-plugins - org.wso2.carbon.device.mgt.iot.camera.plugin.impl - provided - - - - - org.codehaus.jackson - jackson-core-asl - - - org.codehaus.jackson - jackson-jaxrs - - - javax - javaee-web-api - provided - - - javax.ws.rs - jsr311-api - provided - - - commons-httpclient.wso2 - commons-httpclient - provided - - - - org.wso2.carbon - org.wso2.carbon.utils - provided - - - 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.wso2 - commons-codec - - - - org.wso2.carbon.devicemgt - org.wso2.carbon.apimgt.annotations - provided - - - - org.igniterealtime.smack.wso2 - smack - provided - - - org.igniterealtime.smack.wso2 - smackx - provided - - - org.wso2.carbon.devicemgt - org.wso2.carbon.apimgt.webapp.publisher - provided - - - - - - - - - maven-compiler-plugin - - UTF-8 - ${wso2.maven.compiler.source} - ${wso2.maven.compiler.target} - - - - maven-war-plugin - - camera_mgt - - - - - - diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml deleted file mode 100644 index bd3c82af6..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/pom.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - camera-plugin - org.wso2.carbon.devicemgt-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.device.mgt.iot.camera.plugin.impl - bundle - WSO2 Carbon - IoT Server Camera Management Plugin - WSO2 Carbon - Camera Management/Control Plugin Implementation - http://wso2.org - - - - - org.apache.felix - maven-scr-plugin - - - maven-compiler-plugin - - 1.7 - 1.7 - - 2.3.2 - - - org.apache.felix - maven-bundle-plugin - 1.4.0 - true - - - ${project.artifactId} - ${project.artifactId} - ${carbon.devicemgt.plugins.version} - IoT Server Camera Impl Bundle - org.wso2.carbon.device.mgt.iot.camera.plugin.internal - - org.osgi.framework, - org.osgi.service.component, - org.apache.commons.logging, - javax.xml.bind.*, - javax.naming, - javax.sql, - javax.xml.bind.annotation.*, - javax.xml.parsers, - javax.net, - javax.net.ssl, - org.w3c.dom, - org.wso2.carbon.device.mgt.common.*, - org.wso2.carbon.device.mgt.common, - org.wso2.carbon.context.*, - org.wso2.carbon.ndatasource.core, - org.wso2.carbon.device.mgt.iot.*, - - - - !org.wso2.carbon.device.mgt.iot.camera.plugin.internal, - org.wso2.carbon.device.mgt.iot.camera.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/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java deleted file mode 100644 index fa9b91d83..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/constants/CameraConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.constants; - -public class CameraConstants { - public final static String DEVICE_TYPE = "camera"; - public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; - public final static String DEVICE_PLUGIN_DEVICE_ID = "CAMERA_DEVICE_ID"; - public final static String STATE_ON = "ON"; - public final static String STATE_OFF = "OFF"; -} diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java deleted file mode 100644 index 1498a4b58..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManager.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl; - - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -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 org.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.CameraDAO; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOException; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOFactory; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dto.IotDevice; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.util.IotDeviceManagementUtil; - -import java.util.ArrayList; -import java.util.List; - - -/** - * This represents the FireAlarm implementation of DeviceManagerService. - */ -public class CameraManager implements DeviceManager { - - private static final IotDeviceManagementDAOFactory iotDeviceManagementDAOFactory = new CameraDAO(); - private static final Log log = LogFactory.getLog(CameraManager.class); - - - @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; - IotDevice iotDevice = IotDeviceManagementUtil.convertToIotDevice(device); - try { - if (log.isDebugEnabled()) { - log.debug("Enrolling a new Camera device : " + device.getDeviceIdentifier()); - } - CameraDAO.beginTransaction(); - status = iotDeviceManagementDAOFactory.getIotDeviceDAO().addIotDevice( - iotDevice); - CameraDAO.commitTransaction(); - } catch (IotDeviceManagementDAOException e) { - try { - CameraDAO.rollbackTransaction(); - } catch (IotDeviceManagementDAOException iotDAOEx) { - String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); - log.warn(msg, iotDAOEx); - } - String msg = "Error while enrolling the Camera device : " + device.getDeviceIdentifier(); - log.error(msg, e); - throw new DeviceManagementException(msg, e); - } - return status; - } - - @Override - public boolean modifyEnrollment(Device device) throws DeviceManagementException { - boolean status; - IotDevice iotDevice = IotDeviceManagementUtil.convertToIotDevice(device); - try { - if (log.isDebugEnabled()) { - log.debug("Modifying the Camera device enrollment data"); - } - CameraDAO.beginTransaction(); - status = iotDeviceManagementDAOFactory.getIotDeviceDAO() - .updateIotDevice(iotDevice); - CameraDAO.commitTransaction(); - } catch (IotDeviceManagementDAOException e) { - try { - CameraDAO.rollbackTransaction(); - } catch (IotDeviceManagementDAOException 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 Camera 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 Camera device : " + deviceId); - } - CameraDAO.beginTransaction(); - status = iotDeviceManagementDAOFactory.getIotDeviceDAO() - .deleteIotDevice(deviceId.getId()); - CameraDAO.commitTransaction(); - } catch (IotDeviceManagementDAOException e) { - try { - CameraDAO.rollbackTransaction(); - } catch (IotDeviceManagementDAOException 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 Camera 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 Camera device : " + deviceId.getId()); - } - IotDevice iotDevice = - iotDeviceManagementDAOFactory.getIotDeviceDAO().getIotDevice( - deviceId.getId()); - if (iotDevice != null) { - isEnrolled = true; - } - } catch (IotDeviceManagementDAOException e) { - String msg = "Error while checking the enrollment status of Camera 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 Camera device : " + deviceId.getId()); - } - IotDevice iotDevice = iotDeviceManagementDAOFactory.getIotDeviceDAO(). - getIotDevice(deviceId.getId()); - device = IotDeviceManagementUtil.convertToDevice(iotDevice); - } catch (IotDeviceManagementDAOException e) { - String msg = "Error while fetching the Camera 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; - IotDevice iotDevice = IotDeviceManagementUtil.convertToIotDevice(device); - try { - if (log.isDebugEnabled()) { - log.debug( - "updating the details of Camera device : " + deviceIdentifier); - } - CameraDAO.beginTransaction(); - status = iotDeviceManagementDAOFactory.getIotDeviceDAO() - .updateIotDevice(iotDevice); - CameraDAO.commitTransaction(); - } catch (IotDeviceManagementDAOException e) { - try { - CameraDAO.rollbackTransaction(); - } catch (IotDeviceManagementDAOException 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 Camera device : " + deviceIdentifier; - log.error(msg, e); - throw new DeviceManagementException(msg, e); - } - return status; - } - - @Override - public List getAllDevices() throws DeviceManagementException { - List devices = null; - try { - if (log.isDebugEnabled()) { - log.debug("Fetching the details of all Camera devices"); - } - List iotDevices = - iotDeviceManagementDAOFactory.getIotDeviceDAO().getAllIotDevices(); - if (iotDevices != null) { - devices = new ArrayList(); - for (IotDevice iotDevice : iotDevices) { - devices.add(IotDeviceManagementUtil.convertToDevice(iotDevice)); - } - } - } catch (IotDeviceManagementDAOException e) { - String msg = "Error while fetching all Camera devices."; - log.error(msg, e); - throw new DeviceManagementException(msg, e); - } - return devices; - } - -} \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java deleted file mode 100644 index a6241b940..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/CameraManagerService.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl; - -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 org.wso2.carbon.device.mgt.iot.camera.plugin.constants.CameraConstants; - -import java.util.List; - -public class CameraManagerService implements DeviceManagementService{ - private DeviceManager deviceManager; - @Override - public String getType() { - return CameraConstants.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 CameraManager(); - } - - @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/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java deleted file mode 100644 index 35571d851..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/CameraDAO.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.iot.camera.plugin.constants.CameraConstants; -import org.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.impl.CameraDeviceDAOImpl; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceDAO; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOException; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOFactory; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOFactoryInterface; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.SQLException; - -public class CameraDAO extends IotDeviceManagementDAOFactory implements IotDeviceManagementDAOFactoryInterface { - - private static final Log log = LogFactory.getLog(CameraDAO.class); - static DataSource dataSource; - private static ThreadLocal currentConnection = new ThreadLocal(); - - public CameraDAO() { - initFireAlarmDAO(); - } - - public static void initFireAlarmDAO() { - dataSource = getDataSourceMap().get(CameraConstants.DEVICE_TYPE); - } - - @Override public IotDeviceDAO getIotDeviceDAO() { - return new CameraDeviceDAOImpl(); - } - - public static void beginTransaction() throws IotDeviceManagementDAOException { - try { - Connection conn = dataSource.getConnection(); - conn.setAutoCommit(false); - currentConnection.set(conn); - } catch (SQLException e) { - throw new IotDeviceManagementDAOException("Error occurred while retrieving datasource connection", e); - } - } - - public static Connection getConnection() throws IotDeviceManagementDAOException { - if (currentConnection.get() == null) { - try { - currentConnection.set(dataSource.getConnection()); - } catch (SQLException e) { - throw new IotDeviceManagementDAOException("Error occurred while retrieving data source connection", e); - } - } - return currentConnection.get(); - } - - public static void commitTransaction() throws IotDeviceManagementDAOException { - 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 IotDeviceManagementDAOException("Error occurred while committing the transaction", e); - } finally { - closeConnection(); - } - } - - public static void closeConnection() throws IotDeviceManagementDAOException { - - 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 IotDeviceManagementDAOException { - 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 IotDeviceManagementDAOException("Error occurred while rollback the transaction", e); - } finally { - closeConnection(); - } - } -} \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java deleted file mode 100644 index 59e68335b..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/dao/impl/CameraDeviceDAOImpl.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.impl; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.iot.camera.plugin.constants.CameraConstants; -import org.wso2.carbon.device.mgt.iot.camera.plugin.impl.dao.CameraDAO; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceDAO; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.IotDeviceManagementDAOException; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dao.util.IotDeviceManagementDAOUtil; -import org.wso2.carbon.device.mgt.iot.util.iotdevice.dto.IotDevice; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Implements IotDeviceDAO for camera Devices. - */ -public class CameraDeviceDAOImpl implements IotDeviceDAO{ - - - private static final Log log = LogFactory.getLog(CameraDeviceDAOImpl.class); - - @Override - public IotDevice getIotDevice(String iotDeviceId) - throws IotDeviceManagementDAOException { - Connection conn = null; - PreparedStatement stmt = null; - IotDevice iotDevice = null; - ResultSet resultSet = null; - try { - conn = CameraDAO.getConnection(); - String selectDBQuery = - "SELECT CAMERA_DEVICE_ID, DEVICE_NAME" + - " FROM CAMERA_DEVICE WHERE CAMERA_DEVICE_ID = ?"; - stmt = conn.prepareStatement(selectDBQuery); - stmt.setString(1, iotDeviceId); - resultSet = stmt.executeQuery(); - - if (resultSet.next()) { - iotDevice = new IotDevice(); - iotDevice.setIotDeviceName(resultSet.getString( - CameraConstants.DEVICE_PLUGIN_DEVICE_NAME)); - Map propertyMap = new HashMap(); - - - - iotDevice.setDeviceProperties(propertyMap); - - if (log.isDebugEnabled()) { - log.debug("Camera device " + iotDeviceId + " data has been fetched from " + - "Camera database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while fetching Camera device : '" + iotDeviceId + "'"; - log.error(msg, e); - throw new IotDeviceManagementDAOException(msg, e); - } finally { - IotDeviceManagementDAOUtil.cleanupResources(stmt, resultSet); - CameraDAO.closeConnection(); - } - - return iotDevice; - } - - @Override - public boolean addIotDevice(IotDevice iotDevice) - throws IotDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = CameraDAO.getConnection(); - String createDBQuery = - "INSERT INTO CAMERA_DEVICE(CAMERA_DEVICE_ID, DEVICE_NAME) VALUES (?, ?)"; - - stmt = conn.prepareStatement(createDBQuery); - stmt.setString(1, iotDevice.getIotDeviceId()); - stmt.setString(2,iotDevice.getIotDeviceName()); - if (iotDevice.getDeviceProperties() == null) { - iotDevice.setDeviceProperties(new HashMap()); - } - - - int rows = stmt.executeUpdate(); - if (rows > 0) { - status = true; - if (log.isDebugEnabled()) { - log.debug("Camera device " + iotDevice.getIotDeviceId() + " data has been" + - " added to the Camere database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while adding the Camera device '" + - iotDevice.getIotDeviceId() + "' to the Camera db."; - log.error(msg, e); - throw new IotDeviceManagementDAOException(msg, e); - } finally { - IotDeviceManagementDAOUtil.cleanupResources(stmt, null); - } - return status; - } - - @Override - public boolean updateIotDevice(IotDevice iotDevice) - throws IotDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = CameraDAO.getConnection(); - String updateDBQuery = - "UPDATE CAMERA_DEVICE SET DEVICE_NAME = ? WHERE CAMERA_DEVICE_ID = ?"; - - stmt = conn.prepareStatement(updateDBQuery); - - if (iotDevice.getDeviceProperties() == null) { - iotDevice.setDeviceProperties(new HashMap()); - } - stmt.setString(1, iotDevice.getIotDeviceName()); - - stmt.setString(2, iotDevice.getIotDeviceId()); - int rows = stmt.executeUpdate(); - if (rows > 0) { - status = true; - if (log.isDebugEnabled()) { - log.debug("Camera device " + iotDevice.getIotDeviceId() + " data has been" + - " modified."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while modifying the Camera device '" + - iotDevice.getIotDeviceId() + "' data."; - log.error(msg, e); - throw new IotDeviceManagementDAOException(msg, e); - } finally { - IotDeviceManagementDAOUtil.cleanupResources(stmt, null); - } - return status; - } - - @Override - public boolean deleteIotDevice(String iotDeviceId) - throws IotDeviceManagementDAOException { - boolean status = false; - Connection conn = null; - PreparedStatement stmt = null; - try { - conn = CameraDAO.getConnection(); - String deleteDBQuery = - "DELETE FROM CAMERA_DEVICE WHERE CAMERA_DEVICE_ID = ?"; - stmt = conn.prepareStatement(deleteDBQuery); - stmt.setString(1, iotDeviceId); - int rows = stmt.executeUpdate(); - if (rows > 0) { - status = true; - if (log.isDebugEnabled()) { - log.debug("Camera device " + iotDeviceId + " data has deleted from the Camera database."); - } - } - } catch (SQLException e) { - String msg = "Error occurred while deleting Camera device " + iotDeviceId; - log.error(msg, e); - throw new IotDeviceManagementDAOException(msg, e); - } finally { - IotDeviceManagementDAOUtil.cleanupResources(stmt, null); - } - return status; - } - - @Override - public List getAllIotDevices() - throws IotDeviceManagementDAOException { - - Connection conn = null; - PreparedStatement stmt = null; - ResultSet resultSet = null; - IotDevice iotDevice; - List iotDevices = new ArrayList(); - - try { - conn = CameraDAO.getConnection(); - String selectDBQuery = - "SELECT CAMERA_DEVICE_ID, DEVICE_NAME " + - "FROM CAMERA_DEVICE"; - stmt = conn.prepareStatement(selectDBQuery); - resultSet = stmt.executeQuery(); - while (resultSet.next()) { - iotDevice = new IotDevice(); - iotDevice.setIotDeviceId(resultSet.getString(CameraConstants.DEVICE_PLUGIN_DEVICE_ID)); - iotDevice.setIotDeviceName(resultSet.getString(CameraConstants.DEVICE_PLUGIN_DEVICE_NAME)); - - Map propertyMap = new HashMap(); - - iotDevice.setDeviceProperties(propertyMap); - iotDevices.add(iotDevice); - } - if (log.isDebugEnabled()) { - log.debug("All Camera device details have fetched from Firealarm database."); - } - return iotDevices; - } catch (SQLException e) { - String msg = "Error occurred while fetching all Camera device data'"; - log.error(msg, e); - throw new IotDeviceManagementDAOException(msg, e); - } finally { - IotDeviceManagementDAOUtil.cleanupResources(stmt, resultSet); - CameraDAO.closeConnection(); - } - - } - - } \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java deleted file mode 100644 index b47c6d84a..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/impl/util/VirtualFireAlarmUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.impl.util; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.Map; - -/** - * Contains utility methods used by FireAlarm plugin. - */ -public class VirtualFireAlarmUtils { - - private static Log log = LogFactory.getLog(VirtualFireAlarmUtils.class); - - public static String getDeviceProperty(Map deviceProperties, String property) { - - String deviceProperty = deviceProperties.get(property); - - if (deviceProperty == null) { - return ""; - } - - return deviceProperty; - } - - -} diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java deleted file mode 100644 index 3546dd987..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.plugin.impl/src/main/java/org/wso2/carbon/device/mgt/iot/camera/plugin/internal/CameraManagementServiceComponent.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.camera.plugin.internal; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -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; -import org.wso2.carbon.device.mgt.iot.camera.plugin.impl.CameraManagerService; -import org.wso2.carbon.device.mgt.iot.service.DeviceTypeService; - - -/** - * @scr.component name="org.wso2.carbon.device.mgt.iot.camera.plugin.internal - * .CameraManagementServiceComponent" - * immediate="true" - * @scr.reference name="org.wso2.carbon.device.mgt.iot.service.DeviceTypeServiceImpl" - * interface="org.wso2.carbon.device.mgt.iot.service.DeviceTypeService" - * cardinality="1..1" - * policy="dynamic" - * bind="setDeviceTypeService" - * unbind="unsetDeviceTypeService" - */ -public class CameraManagementServiceComponent { - - private static final Log log = LogFactory.getLog(CameraManagementServiceComponent.class); - private ServiceRegistration firealarmServiceRegRef; - - protected void activate(ComponentContext ctx) { - if (log.isDebugEnabled()) { - log.debug("Activating Camera Device Management Service Component"); - } - try { - BundleContext bundleContext = ctx.getBundleContext(); - firealarmServiceRegRef = - bundleContext.registerService(DeviceManagementService.class.getName(), - new CameraManagerService(), null); - - if (log.isDebugEnabled()) { - log.debug( - "Camera Device Management Service Component has been successfully activated"); - } - } catch (Throwable e) { - log.error( - "Error occurred while activating Camera Device Management Service Component", e); - } - } - - protected void deactivate(ComponentContext ctx) { - if (log.isDebugEnabled()) { - log.debug("De-activating Camera Device Management Service Component"); - } - try { - if (firealarmServiceRegRef != null) { - firealarmServiceRegRef.unregister(); - } - - if (log.isDebugEnabled()) { - log.debug( - "Camera Device Management Service Component has been successfully de-activated"); - } - } catch (Throwable e) { - log.error( - "Error occurred while de-activating Camera Device Management bundle", e); - } - } - - protected void setDeviceTypeService(DeviceTypeService deviceTypeService) { - /* This is to avoid this component getting initialized before the common registered */ - if (log.isDebugEnabled()) { - log.debug("Data source service set to mobile service component"); - } - } - - protected void unsetDeviceTypeService(DeviceTypeService deviceTypeService) { - //do nothing - } - - -} diff --git a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml b/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml deleted file mode 100644 index 89bc215a2..000000000 --- a/components/iot-plugins/camera-plugin/org.wso2.carbon.device.mgt.iot.camera.ui/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - camera-plugin - org.wso2.carbon.devicemgt-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.device.mgt.iot.camera.ui - WSO2 Carbon - IoT Server Camera UI - pom - - - - - maven-assembly-plugin - 2.5.5 - - ${project.artifactId}-${carbon.device.mgt.version} - false - - src/assembly/src.xml - - - - - create-archive - package - - single - - - - - - - - \ No newline at end of file diff --git a/components/iot-plugins/camera-plugin/pom.xml b/components/iot-plugins/camera-plugin/pom.xml deleted file mode 100644 index ebeed88cc..000000000 --- a/components/iot-plugins/camera-plugin/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - org.wso2.carbon.devicemgt-plugins - iot-plugins - 2.1.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.wso2.carbon.devicemgt-plugins - camera-plugin - pom - WSO2 Carbon - Arduino Plugin - http://wso2.org - - - org.wso2.carbon.device.mgt.iot.camera.controller.service.impl - org.wso2.carbon.device.mgt.iot.camera.manager.service.impl - org.wso2.carbon.device.mgt.iot.camera.plugin.impl - org.wso2.carbon.device.mgt.iot.camera.ui - - - - - - - org.apache.felix - maven-scr-plugin - 1.7.2 - - - generate-scr-scrdescriptor - - scr - - - - - - - - - diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java index 58841062b..e1f8431bc 100644 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/DevicesManagerService.java @@ -22,7 +22,10 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.common.*; +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.common.configuration.mgt.TenantConfiguration; import org.wso2.carbon.device.mgt.common.license.mgt.License; import org.wso2.carbon.device.mgt.core.dto.DeviceType; @@ -33,7 +36,17 @@ import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; import javax.jws.WebService; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +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.Response; import java.util.ArrayList; @@ -97,22 +110,6 @@ import java.util.List; } } - @Path("/device/user/{username}/ungrouped") - @GET - @Consumes("application/json") - @Produces("application/json") - public Device[] getUnGroupedDevices(@PathParam("username") String username){ - try{ - List devices = this.getServiceProvider().getUnGroupedDevices(username); - return this.getActiveDevices(devices); - } catch (DeviceManagementException e) { - response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); - return null; - } finally { - this.endTenantFlow(); - } - } - @Path("/device/user/{username}/all/count") @GET @Consumes("application/json") @@ -205,66 +202,6 @@ import java.util.List; } } - @Path("/device/enrollment/invitation") - @POST - @Consumes("application/json") - @Produces("application/json") - public void sendEnrolmentInvitation(@FormParam("messageBody") String messageBody, - @FormParam("mailTo") String[] mailTo, @FormParam("ccList") String[] ccList, - @FormParam("bccList") String[] bccList, @FormParam("subject") String subject, - @FormParam("firstName") String firstName, @FormParam("enrolmentUrl") String enrolmentUrl, - @FormParam("title") String title, @FormParam("password") String password, - @FormParam("userName") String userName){ - EmailMessageProperties config = new EmailMessageProperties(); - config.setMessageBody(messageBody); - config.setMailTo(mailTo); - config.setCcList(ccList); - config.setBccList(bccList); - config.setSubject(subject); - config.setFirstName(firstName); - config.setEnrolmentUrl(enrolmentUrl); - config.setTitle(title); - config.setUserName(userName); - config.setPassword(password); - try { - this.getServiceProvider().sendEnrolmentInvitation(config); - } catch (DeviceManagementException e) { - response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); - } finally { - this.endTenantFlow(); - } - } - - @Path("/device/registration/invitation") - @POST - @Consumes("application/json") - @Produces("application/json") - public void sendRegistrationEmail(@FormParam("messageBody") String messageBody, - @FormParam("mailTo") String[] mailTo, @FormParam("ccList") String[] ccList, - @FormParam("bccList") String[] bccList, @FormParam("subject") String subject, - @FormParam("firstName") String firstName, @FormParam("enrolmentUrl") String enrolmentUrl, - @FormParam("title") String title, @FormParam("password") String password, - @FormParam("userName") String userName){ - EmailMessageProperties config = new EmailMessageProperties(); - config.setMessageBody(messageBody); - config.setMailTo(mailTo); - config.setCcList(ccList); - config.setBccList(bccList); - config.setSubject(subject); - config.setFirstName(firstName); - config.setEnrolmentUrl(enrolmentUrl); - config.setTitle(title); - config.setUserName(userName); - config.setPassword(password); - try { - this.getServiceProvider().sendRegistrationEmail(config); - } catch (DeviceManagementException e) { - response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); - } finally { - this.endTenantFlow(); - } - } - @Path("/device/type/{type}/config") @GET @Consumes("application/json") @@ -394,10 +331,12 @@ import java.util.List; @Produces("application/json") boolean modifyEnrollment(@PathParam("type") String type, @PathParam("identifier") String identifier, @FormParam("name") String name, @FormParam("description") String description, - @FormParam("groupId") int groupId, @FormParam("enrollmentId") int enrollmentId, - @FormParam("dateOfEnrolment") long dateOfEnrolment, @FormParam("dateOfLastUpdate") long dateOfLastUpdate, - @FormParam("ownership") EnrolmentInfo.OwnerShip ownership, @FormParam("status") EnrolmentInfo.Status status, - @FormParam("owner") String owner){ + @FormParam("enrollmentId") int enrollmentId, + @FormParam("dateOfEnrolment") long dateOfEnrolment, + @FormParam("dateOfLastUpdate") long dateOfLastUpdate, + @FormParam("ownership") EnrolmentInfo.OwnerShip ownership, + @FormParam("status") EnrolmentInfo.Status status, + @FormParam("owner") String owner) { EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); enrolmentInfo.setId(enrollmentId); @@ -412,7 +351,6 @@ import java.util.List; device.setDeviceIdentifier(identifier); device.setName(name); device.setDescription(description); - device.setGroupId(groupId); device.setEnrolmentInfo(enrolmentInfo); try { return this.getServiceProvider().modifyEnrollment(device); @@ -430,10 +368,12 @@ import java.util.List; @Produces("application/json") boolean enrollDevice(@FormParam("type") String type, @FormParam("identifier") String identifier, @FormParam("name") String name, @FormParam("description") String description, - @FormParam("groupId") int groupId, @FormParam("enrollmentId") int enrollmentId, - @FormParam("dateOfEnrolment") long dateOfEnrolment, @FormParam("dateOfLastUpdate") long dateOfLastUpdate, - @FormParam("ownership") EnrolmentInfo.OwnerShip ownership, @FormParam("status") EnrolmentInfo.Status status, - @FormParam("owner") String owner){ + @FormParam("enrollmentId") int enrollmentId, + @FormParam("dateOfEnrolment") long dateOfEnrolment, + @FormParam("dateOfLastUpdate") long dateOfLastUpdate, + @FormParam("ownership") EnrolmentInfo.OwnerShip ownership, + @FormParam("status") EnrolmentInfo.Status status, + @FormParam("owner") String owner) { EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); enrolmentInfo.setId(enrollmentId); @@ -448,7 +388,6 @@ import java.util.List; device.setDeviceIdentifier(identifier); device.setName(name); device.setDescription(description); - device.setGroupId(groupId); device.setEnrolmentInfo(enrolmentInfo); try { return this.getServiceProvider().enrollDevice(device); diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java index 496410386..4e109c9ca 100644 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java @@ -27,10 +27,10 @@ import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; -import org.wso2.carbon.device.mgt.group.common.DeviceGroup; -import org.wso2.carbon.device.mgt.group.common.GroupManagementException; -import org.wso2.carbon.device.mgt.group.common.GroupUser; -import org.wso2.carbon.device.mgt.group.core.providers.GroupManagementServiceProvider; +import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; +import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; +import org.wso2.carbon.device.mgt.common.group.mgt.GroupUser; +import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; import org.wso2.carbon.device.mgt.iot.util.ResponsePayload; import javax.jws.WebService; @@ -73,7 +73,7 @@ public class GroupManagerService { private HttpServletResponse response; private PrivilegedCarbonContext ctx; - private GroupManagementServiceProvider getServiceProvider() { + private GroupManagementProviderService getServiceProvider() { String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); String username = CarbonContext.getThreadLocalCarbonContext().getUsername(); PrivilegedCarbonContext.startTenantFlow(); @@ -82,7 +82,7 @@ public class GroupManagerService { if (log.isDebugEnabled()) { log.debug("Getting thread local carbon context for tenant domain: " + tenantDomain); } - return (GroupManagementServiceProvider) ctx.getOSGiService(GroupManagementServiceProvider.class, null); + return (GroupManagementProviderService) ctx.getOSGiService(GroupManagementProviderService.class, null); } private void endTenantFlow() { @@ -108,7 +108,7 @@ public class GroupManagerService { group.setDateOfLastUpdate(new Date().getTime()); boolean isAdded = false; try { - GroupManagementServiceProvider groupManagementService = this.getServiceProvider(); + GroupManagementProviderService groupManagementService = this.getServiceProvider(); int groupId = groupManagementService.createGroup(group, DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_PERMISSIONS); if (groupId == -2) { ResponsePayload responsePayload = new ResponsePayload(); @@ -151,7 +151,7 @@ public class GroupManagerService { return false; } try { - GroupManagementServiceProvider groupManagementService = this.getServiceProvider(); + GroupManagementProviderService groupManagementService = this.getServiceProvider(); DeviceGroup group = groupManagementService.getGroup(groupId); group.setName(name); group.setDescription(description); @@ -219,7 +219,7 @@ public class GroupManagerService { @FormParam("username") String username) { DeviceGroup[] deviceGroups = null; try { - List groups = this.getServiceProvider().findGroups(groupName, username); + List groups = this.getServiceProvider().findInGroups(groupName, username); deviceGroups = new DeviceGroup[groups.size()]; response.setStatus(Response.Status.OK.getStatusCode()); groups.toArray(deviceGroups); @@ -240,7 +240,7 @@ public class GroupManagerService { @QueryParam("permission") String permission) { DeviceGroup[] deviceGroups = null; try { - GroupManagementServiceProvider groupManagementService = this.getServiceProvider(); + GroupManagementProviderService groupManagementService = this.getServiceProvider(); List groups; if (permission != null) { groups = groupManagementService.getGroups(username, permission); diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java deleted file mode 100644 index 4c696654a..000000000 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/StatsManagerService.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2015, 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.wso2.carbon.device.mgt.iot.api; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.analytics.common.AnalyticsDataRecord; -import org.wso2.carbon.device.mgt.analytics.exception.DeviceManagementAnalyticsException; -import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; -import javax.jws.WebService; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -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.Response; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -@WebService public class StatsManagerService { - - private static Log log = LogFactory.getLog(StatsManagerService.class); - - @Context //injected response proxy supporting multiple thread - private HttpServletResponse response; - //TODO THIS NEEDS TO BE REMOVED. - @Path("/stats/device/type/{type}/identifier/{identifier}") - @GET - @Consumes("application/json") - @Produces("application/json") - public DeviceUsageDTO[] getDeviceStats(@PathParam("type") String type, @PathParam("identifier") String identifier, - @QueryParam("table") String table, @QueryParam("column") String column, @QueryParam("username") String user, - @QueryParam("from") long from, @QueryParam("to") long to) { - - String fromDate = String.valueOf(from); - String toDate = String.valueOf(to); - - List deviceUsageDTOs = new ArrayList<>(); - PrivilegedCarbonContext.startTenantFlow(); - PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); - ctx.setTenantDomain("carbon.super", true); - DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx - .getOSGiService(DeviceAnalyticsService.class, null); - String query = "owner:" + user + " AND deviceId:" + identifier + " AND deviceType:" + type + - " AND time : [" + fromDate + " TO " + toDate + "]"; - try { - List records = deviceAnalyticsService.getAllEventsForDevice(table, query); - - Collections.sort(records, new Comparator() { - @Override - public int compare(AnalyticsDataRecord o1, AnalyticsDataRecord o2) { - long t1 = (Long) o1.getValue("time"); - long t2 = (Long) o2.getValue("time"); - if (t1 < t2) { - return -1; - } else if (t1 > t2) { - return 1; - } else { - return 0; - } - } - }); - - for (AnalyticsDataRecord record : records) { - DeviceUsageDTO deviceUsageDTO = new DeviceUsageDTO(); - deviceUsageDTO.setTime("" + (long)record.getValue("time")); - deviceUsageDTO.setValue("" + (float) record.getValue(column.toLowerCase())); - deviceUsageDTOs.add(deviceUsageDTO); - } - return deviceUsageDTOs.toArray(new DeviceUsageDTO[deviceUsageDTOs.size()]); - } catch (DeviceManagementAnalyticsException e) { - String errorMsg= "Error on retrieving stats on table " + table + " with query " + query; - log.error(errorMsg); - response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); - return deviceUsageDTOs.toArray(new DeviceUsageDTO[deviceUsageDTOs.size()]); - } finally { - PrivilegedCarbonContext.endTenantFlow(); - } - } - -} diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml index 1112d721e..739f0bee9 100644 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -45,16 +45,6 @@ - - - - - - - - - - - - - - - - - - - diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml index cfdc32dbc..27ad2fed1 100644 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml @@ -66,25 +66,20 @@ javax.xml.namespace;resolution:=optional, javax.xml.validation;resolution:=optional, org.apache.commons.codec.binary, - org.apache.commons.collections.map, org.apache.http.*, org.apache.commons.io.*, org.apache.commons.logging.*, org.json;version="${commons-json.version}", org.wso2.carbon.base.*, org.wso2.carbon.databridge.*, - org.wso2.carbon.user.api, - org.wso2.carbon.user.core.service, org.osgi.framework, org.osgi.service.component, javax.xml.bind.*;resolution:=optional, - javax.naming;resolution:=optional, - javax.sql;resolution:=optional, javax.xml.bind.annotation.*;resolution:=optional, javax.xml.parsers.*;resolution:=optional, - javax.net;resolution:=optional, - javax.net.ssl;resolution:=optional, javax.crypto, + javax.ws.rs.core, + javax.xml, org.apache.tomcat.util.codec.binary, org.w3c.dom;resolution:=optional, org.wso2.carbon.core;version="${carbon.kernel.version.range}", @@ -92,7 +87,6 @@ org.wso2.carbon.device.mgt.common.*, org.wso2.carbon.device.mgt.core.*, org.wso2.carbon.context.*;version="${carbon.kernel.version.range}", - org.wso2.carbon.ndatasource.core;version="${carbon.kernel.version.range}", org.eclipse.paho.client.mqttv3.*;version="${eclipse.paho.version}" @@ -144,6 +138,12 @@ org.wso2.carbon.devicemgt org.wso2.carbon.device.mgt.core + + + org.apache.httpcomponents.wso2 + httpclient + + org.wso2.carbon diff --git a/components/iot-plugins/pom.xml b/components/iot-plugins/pom.xml index 0020ee7f1..45e660e7c 100644 --- a/components/iot-plugins/pom.xml +++ b/components/iot-plugins/pom.xml @@ -27,20 +27,18 @@ 4.0.0 - org.wso2.carbon.devicemgt-plugins iot-plugins pom WSO2 Carbon - IoT Plugins http://wso2.org - androidsense-plugin - arduino-plugin - camera-plugin - digital-display-plugin - drone-analyzer-plugin - raspberrypi-plugin - virtual-fire-alarm-plugin + + + + + + iot-base-plugin diff --git a/pom.xml b/pom.xml index 318c7e3df..c31949282 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ components/mobile-plugins - + components/iot-plugins features/mobile-plugins-feature @@ -1030,6 +1030,10 @@ + + 1.7 + 1.7 + 4.4.3 [4.4.0, 4.5.0) From 4f5b5188ea067c077624d2f322660bc649217224 Mon Sep 17 00:00:00 2001 From: charithag Date: Tue, 29 Mar 2016 18:32:12 +0530 Subject: [PATCH 07/10] Updated with core changes --- .../org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java index 4e109c9ca..335a3c79e 100644 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot.api/src/main/java/org/wso2/carbon/device/mgt/iot/api/GroupManagerService.java @@ -475,7 +475,7 @@ public class GroupManagerService { @GET @Consumes("application/json") @Produces("application/json") - public PaginationResult getDevices(@PathParam("groupId") int groupId, + public List getDevices(@PathParam("groupId") int groupId, @QueryParam("index") int index, @QueryParam("limit") int limit) { try { From f74a8ddf0d489d128e51e2c439ef8aa7fe1c93f9 Mon Sep 17 00:00:00 2001 From: charithag Date: Wed, 30 Mar 2016 01:57:31 +0530 Subject: [PATCH 08/10] Add device type plugins and features related to emm with IoTS base feature. --- .../org.wso2.carbon.device.mgt.iot/pom.xml | 7 +- .../pom.xml | 4 +- .../android/ConfigurationMgtService.java | 8 +- .../android/DeviceManagementService.java | 4 +- .../services/android/EnrollmentService.java | 4 +- .../services/android/OperationMgtService.java | 4 +- .../services/android/PolicyMgtService.java | 6 +- .../android/bean/AndroidOperation.java | 4 +- .../android/bean/ApplicationInstallation.java | 8 +- .../bean/ApplicationUninstallation.java | 8 +- .../android/bean/BlacklistApplications.java | 8 +- .../mdm/services/android/bean/Camera.java | 8 +- .../android/bean/DeviceEncryption.java | 8 +- .../services/android/bean/Disenrollment.java | 4 +- .../mdm/services/android/bean/LockCode.java | 4 +- .../services/android/bean/Notification.java | 4 +- .../services/android/bean/PasscodePolicy.java | 4 +- .../mdm/services/android/bean/WebClip.java | 4 +- .../mdm/services/android/bean/Wifi.java | 8 +- .../mdm/services/android/bean/WipeData.java | 4 +- .../ApplicationInstallationBeanWrapper.java | 4 +- .../ApplicationUninstallationBeanWrapper.java | 4 +- .../BlacklistApplicationsBeanWrapper.java | 4 +- .../bean/wrapper/CameraBeanWrapper.java | 4 +- .../wrapper/DisenrollmentBeanWrapper.java | 4 +- .../bean/wrapper/EncryptionBeanWrapper.java | 4 +- .../bean/wrapper/LockCodeBeanWrapper.java | 4 +- .../bean/wrapper/NotificationBeanWrapper.java | 4 +- .../wrapper/PasswordPolicyBeanWrapper.java | 4 +- .../bean/wrapper/WebClipBeanWrapper.java | 4 +- .../android/bean/wrapper/WifiBeanWrapper.java | 4 +- .../bean/wrapper/WipeDataBeanWrapper.java | 4 +- .../services/android/common/ErrorHandler.java | 4 +- .../services/android/common/ErrorMessage.java | 4 +- .../common/GsonMessageBodyHandler.java | 4 +- .../exception/AndroidAgentException.java | 4 +- .../exception/AndroidOperationException.java | 8 +- .../exception/BadRequestException.java | 8 +- .../OperationConfigurationException.java | 4 +- .../android/util/AndroidAPIUtils.java | 4 +- .../android/util/AndroidConstants.java | 4 +- .../android/util/AndroidDeviceUtils.java | 8 +- .../services/android/util/DeviceIDHolder.java | 8 +- .../mdm/services/android/util/Message.java | 4 +- .../src/main/webapp/META-INF/permissions.xml | 8 +- .../webapp/META-INF/webapp-classloading.xml | 6 +- .../src/main/webapp/WEB-INF/cxf-servlet.xml | 6 +- .../src/main/webapp/WEB-INF/web.xml | 2 +- .../src/main/webapp/servicelist.css | 18 + .../pom.xml | 63 ++ .../src/assembly/src.xml | 36 + .../device-view.hbs | 174 +++++ .../device-view.js | 66 ++ .../device-view.json | 3 + .../public/js/device-detail.js | 77 ++ .../public/js/load-map.js | 56 ++ .../policy-edit.hbs | 1 + .../policy-edit.json | 3 + .../policy-view.hbs | 1 + .../policy-view.json | 3 + .../policy-wizard.hbs | 1 + .../policy-wizard.json | 3 + .../public/asset/android-agent.apk | Bin 0 -> 2894105 bytes .../public/images/android-icon.png | Bin 0 -> 7932 bytes .../public/images/android_device.png | Bin 0 -> 317443 bytes .../public/images/thumb.png | Bin 0 -> 6035 bytes .../type-view.hbs | 146 ++++ .../type-view.js | 24 + .../type-view.json | 3 + .../templates/hidden-operations-android.hbs | 246 +++++++ .../impl/AndroidDeviceManagementService.java | 19 +- .../mobile-plugins/android-plugin/pom.xml | 35 +- .../pom.xml | 23 +- .../org/wso2/carbon/mdm/api/Certificate.java | 197 +++++ .../wso2/carbon/mdm/api/Configuration.java | 19 +- .../org/wso2/carbon/mdm/api/Operation.java | 7 +- .../java/org/wso2/carbon/mdm/api/Policy.java | 44 -- .../java/org/wso2/carbon/mdm/api/Role.java | 32 + .../java/org/wso2/carbon/mdm/api/User.java | 273 ++++--- .../CredentialManagementResponseBuilder.java | 105 +++ .../wso2/carbon/mdm/api/util/MDMAPIUtils.java | 30 + .../mdm/beans/EnrollmentCertificate.java | 50 ++ .../wso2/carbon/mdm/beans/UserWrapper.java | 10 +- .../mdm/exception/BadRequestException.java | 31 + .../wso2/carbon/mdm/exception/Message.java | 41 ++ .../src/main/webapp/META-INF/permissions.xml | 680 ++++++++++++------ .../src/main/webapp/WEB-INF/cxf-servlet.xml | 14 +- .../mobile-plugins/mobile-base-plugin/pom.xml | 36 +- components/mobile-plugins/pom.xml | 36 +- .../discovery/beans/package-info.java | 22 - .../services/wstep/beans/package-info.java | 27 - .../services/xcep/beans/package-info.java | 23 - .../src/main/resources/properties.xml | 26 - .../pom.xml | 4 +- .../windows/common/PluginConstants.java | 6 +- .../windows/common/SyncmlCommandType.java | 6 +- .../windows/common/beans/CacheEntry.java | 6 +- .../windows/common/beans/Token.java | 6 +- .../common/beans/WindowsPluginProperties.java | 6 +- .../exceptions/AuthenticationException.java | 6 +- .../exceptions/BadRequestException.java | 6 +- .../CertificateGenerationException.java | 6 +- .../exceptions/FileOperationException.java | 6 +- .../KeyStoreGenerationException.java | 6 +- .../common/exceptions/MDMAPIException.java | 6 +- .../SyncmlMessageFormatException.java | 6 +- .../exceptions/SyncmlOperationException.java | 6 +- .../exceptions/WAPProvisioningException.java | 6 +- .../WindowsConfigurationException.java | 6 +- .../WindowsDeviceEnrolmentException.java | 6 +- .../WindowsOperationsException.java | 8 +- .../common/util/AuthenticationInfo.java | 8 +- .../windows/common/util/BSTValidator.java | 8 +- .../ConfigInitializerContextListener.java | 6 +- .../windows/common/util/DeviceIDHolder.java | 8 +- .../windows/common/util/DeviceUtil.java | 6 +- .../windows/common/util/ErrorHandler.java | 6 +- .../windows/common/util/ErrorMessage.java | 6 +- .../common/util/GsonMessageBodyHandler.java | 6 +- .../windows/common/util/Message.java | 6 +- .../common/util/SOAPSecurityHandler.java | 6 +- .../common/util/UsernameTokenValidator.java | 6 +- .../windows/common/util/WindowsAPIUtils.java | 6 +- .../common/util/WindowsDeviceUtils.java | 6 +- .../windows/operations/AddTag.java | 6 +- .../windows/operations/Alert.java | 6 +- .../windows/operations/AtomicTag.java | 6 +- .../windows/operations/ChallengeTag.java | 6 +- .../windows/operations/Credential.java | 6 +- .../windows/operations/DeleteTag.java | 6 +- .../windows/operations/ExecuteTag.java | 6 +- .../windows/operations/Get.java | 6 +- .../windows/operations/Item.java | 6 +- .../windows/operations/MetaTag.java | 6 +- .../windows/operations/Replace.java | 6 +- .../windows/operations/Results.java | 6 +- .../windows/operations/SequenceTag.java | 6 +- .../windows/operations/Source.java | 6 +- .../windows/operations/Status.java | 6 +- .../windows/operations/SyncmlBody.java | 6 +- .../windows/operations/SyncmlDocument.java | 6 +- .../windows/operations/SyncmlHeader.java | 6 +- .../windows/operations/Target.java | 6 +- .../operations/WindowsOperationException.java | 6 +- .../windows/operations/util/Constants.java | 6 +- .../windows/operations/util/DeviceInfo.java | 6 +- .../operations/util/OperationCode.java | 6 +- .../operations/util/OperationReply.java | 6 +- .../operations/util/OperationUtils.java | 6 +- .../operations/util/SyncmlCredentials.java | 6 +- .../operations/util/SyncmlGenerator.java | 6 +- .../windows/operations/util/SyncmlParser.java | 6 +- .../services/adminoperations/Operations.java | 24 +- .../adminoperations/beans/Device.java | 6 +- .../adminoperations/beans/Disenrollment.java | 6 +- .../beans/OperationRequest.java | 6 +- .../beans/OperationResponse.java | 6 +- .../beans/StorageEncryption.java | 6 +- .../wrapper/DisenrollmentBeanWrapper.java | 6 +- .../beans/wrapper/EncryptBeanWrapper.java | 6 +- .../adminoperations/impl/OperationsImpl.java | 6 +- .../adminoperations/util/OperationStore.java | 24 +- .../windows/services/authbst/BSTProvider.java | 6 +- .../services/authbst/beans/Credentials.java | 6 +- .../authbst/impl/BSTProviderImpl.java | 6 +- .../ConfigurationMgtService.java | 6 +- .../DeviceManagementService.java | 6 +- .../services/discovery/DiscoveryService.java | 6 +- .../discovery/beans/DiscoveryRequest.java | 6 +- .../discovery/beans/DiscoveryResponse.java | 6 +- .../discovery/beans/package-info.java | 22 + .../discovery/impl/DiscoveryServiceImpl.java | 6 +- .../policymgtservice/PolicyMgtService.java | 6 +- .../services/syncml/SyncmlService.java | 6 +- .../services/syncml/beans/BasicOperation.java | 6 +- .../services/syncml/beans/PasscodePolicy.java | 6 +- .../services/syncml/beans/Profile.java | 6 +- .../windows/services/syncml/beans/Wifi.java | 6 +- .../syncml/impl/SyncmlServiceImpl.java | 6 +- .../services/syncml/util/PolicyManager.java | 6 +- .../services/syncml/util/SyncmlUtils.java | 6 +- .../wstep/CertificateEnrollmentService.java | 6 +- .../wstep/beans/AdditionalContext.java | 6 +- .../wstep/beans/BinarySecurityToken.java | 6 +- .../services/wstep/beans/ContextItem.java | 6 +- .../wstep/beans/RequestSecurityToken.java | 6 +- .../beans/RequestSecurityTokenResponse.java | 6 +- .../wstep/beans/RequestedSecurityToken.java | 6 +- .../services/wstep/beans/package-info.java | 27 + .../CertificateEnrollmentServiceImpl.java | 6 +- .../wstep/util/CertificateSigningService.java | 24 +- .../wstep/util/KeyStoreGenerator.java | 24 +- .../services/wstep/util/MessageHandler.java | 24 +- .../CertificateEnrollmentPolicyService.java | 6 +- .../services/xcep/beans/Attributes.java | 6 +- .../windows/services/xcep/beans/CA.java | 6 +- .../services/xcep/beans/CACollection.java | 6 +- .../xcep/beans/CAReferenceCollection.java | 6 +- .../windows/services/xcep/beans/CAURI.java | 6 +- .../services/xcep/beans/CAURICollection.java | 6 +- .../beans/CertificateEnrollmentPolicy.java | 6 +- .../xcep/beans/CertificateValidity.java | 6 +- .../windows/services/xcep/beans/Client.java | 6 +- .../services/xcep/beans/CryptoProviders.java | 6 +- .../xcep/beans/EnrollmentPermission.java | 6 +- .../services/xcep/beans/Extension.java | 6 +- .../xcep/beans/ExtensionCollection.java | 6 +- .../xcep/beans/FilterOIDCollection.java | 6 +- .../services/xcep/beans/GetPolicies.java | 6 +- .../xcep/beans/GetPoliciesResponse.java | 6 +- .../xcep/beans/KeyArchivalAttributes.java | 6 +- .../windows/services/xcep/beans/OID.java | 6 +- .../services/xcep/beans/OIDCollection.java | 6 +- .../xcep/beans/OIDReferenceCollection.java | 6 +- .../services/xcep/beans/ObjectFactory.java | 6 +- .../services/xcep/beans/PolicyCollection.java | 6 +- .../xcep/beans/PrivateKeyAttributes.java | 6 +- .../services/xcep/beans/RARequirements.java | 6 +- .../services/xcep/beans/RequestFilter.java | 6 +- .../windows/services/xcep/beans/Response.java | 6 +- .../windows/services/xcep/beans/Revision.java | 6 +- .../xcep/beans/SupersededPolicies.java | 6 +- .../services/xcep/beans/package-info.java | 23 + ...ertificateEnrollmentPolicyServiceImpl.java | 6 +- .../src/main/resources/properties.xml | 26 + .../src/main/resources/wap-provisioning.xml | 24 +- .../src/main/resources/wso2mdm.jks | Bin .../src/main/webapp/META-INF/permissions.xml | 8 +- .../webapp/META-INF/webapp-classloading.xml | 24 +- .../src/main/webapp/WEB-INF/cxf-servlet.xml | 24 +- .../src/main/webapp/WEB-INF/web.xml | 32 +- .../src/main/webapp/servicelist.css | 18 + .../pom.xml | 63 ++ .../src/assembly/src.xml | 36 + .../device-view.hbs | 14 + .../device-view.json | 3 + .../public/js/device-detail.js | 197 +++++ .../public/js/load-map.js | 56 ++ .../policy-edit.hbs | 1 + .../policy-edit.json | 3 + .../policy-view.hbs | 1 + .../policy-view.json | 3 + .../policy-wizard.hbs | 1 + .../policy-wizard.json | 3 + .../public/images/thumb.png | Bin 0 -> 5195 bytes .../public/images/windows-icon.png | Bin 0 -> 8342 bytes .../public/images/windows_enrollment.png | Bin 0 -> 143764 bytes .../type-view.hbs | 151 ++++ .../type-view.js | 24 + .../type-view.json | 3 + .../impl/WindowsDeviceManagementService.java | 17 +- .../mobile-plugins/windows-plugin/pom.xml | 36 +- .../pom.xml | 192 +++++ .../src/main/resources/build.properties | 19 + .../main/resources/conf/devicemgt-config.xml | 45 ++ .../main/resources/conf/devicemgt-config.xsd | 47 ++ .../src/main/resources/p2.inf | 8 + .../iot-base-plugin-feature/pom.xml | 40 ++ features/iot-plugins-feature/pom.xml | 40 ++ .../pom.xml | 213 ++++++ .../src/main/resources/build.properties | 19 + .../src/main/resources/conf/mobile-config.xml | 71 ++ .../src/main/resources/configs/android.json | 6 + .../main/resources/dbscripts/plugins/h2.sql | 30 + .../resources/dbscripts/plugins/mssql.sql | 29 + .../resources/dbscripts/plugins/mysql.sql | 31 + .../resources/dbscripts/plugins/oracle.sql | 50 ++ .../dbscripts/plugins/postgresql.sql | 29 + .../src/main/resources/p2.inf | 10 + .../android-plugin-feature/pom.xml | 40 ++ .../pom.xml | 81 ++- .../src/main/resources/p2.inf | 4 + .../mobile-base-plugin-feature/pom.xml | 34 +- features/mobile-plugins-feature/pom.xml | 36 +- .../pom.xml | 213 ++++++ .../src/main/resources/build.properties | 19 + .../src/main/resources/configs/windows.json | 6 + .../main/resources/dbscripts/plugins/h2.sql | 30 + .../resources/dbscripts/plugins/mssql.sql | 30 + .../resources/dbscripts/plugins/mysql.sql | 34 + .../resources/dbscripts/plugins/oracle.sql | 51 ++ .../dbscripts/plugins/postgresql.sql | 31 + .../src/main/resources/p2.inf | 9 + .../windows-plugin-feature/pom.xml | 40 ++ pom.xml | 58 +- 285 files changed, 4959 insertions(+), 1291 deletions(-) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/pom.xml (97%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/ConfigurationMgtService.java (96%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/DeviceManagementService.java (98%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/EnrollmentService.java (97%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/OperationMgtService.java (99%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/PolicyMgtService.java (95%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/AndroidOperation.java (87%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationInstallation.java (84%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/ApplicationUninstallation.java (85%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/BlacklistApplications.java (81%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/Camera.java (79%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/DeviceEncryption.java (79%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/Disenrollment.java (87%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/LockCode.java (87%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/Notification.java (87%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/PasscodePolicy.java (93%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/WebClip.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/Wifi.java (81%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/WipeData.java (86%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationInstallationBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/ApplicationUninstallationBeanWrapper.java (90%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/BlacklistApplicationsBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/CameraBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/DisenrollmentBeanWrapper.java (88%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/EncryptionBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/LockCodeBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/NotificationBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/PasswordPolicyBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WebClipBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WifiBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/bean/wrapper/WipeDataBeanWrapper.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorHandler.java (90%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/common/ErrorMessage.java (89%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/common/GsonMessageBodyHandler.java (96%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidAgentException.java (92%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/exception/AndroidOperationException.java (82%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/exception/BadRequestException.java (82%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/exception/OperationConfigurationException.java (88%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidAPIUtils.java (98%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidConstants.java (96%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/util/AndroidDeviceUtils.java (94%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/util/DeviceIDHolder.java (84%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/java/org/wso2/carbon/mdm/services/android/util/Message.java (94%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/webapp/META-INF/permissions.xml (97%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/webapp/META-INF/webapp-classloading.xml (91%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/webapp/WEB-INF/cxf-servlet.xml (96%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/webapp/WEB-INF/web.xml (97%) rename components/mobile-plugins/android-plugin/{org.wso2.carbon.device.mgt.mobile.android.agent => org.wso2.carbon.device.mgt.mobile.android.api}/src/main/webapp/servicelist.css (75%) create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/pom.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/assembly/src.xml create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.hbs create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.js create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.json create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/device-detail.js create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/load-map.js create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.hbs create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.json create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.hbs create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.json create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.hbs create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.json create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/asset/android-agent.apk create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/images/android-icon.png create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/images/android_device.png create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/images/thumb.png create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.hbs create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.js create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.json create mode 100644 components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/CredentialManagementResponseBuilder.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/EnrollmentCertificate.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/BadRequestException.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/Message.java delete mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java delete mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java delete mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java delete mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/pom.xml (98%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/PluginConstants.java (98%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/SyncmlCommandType.java (82%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/CacheEntry.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/Token.java (83%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/beans/WindowsPluginProperties.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/AuthenticationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/BadRequestException.java (86%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/CertificateGenerationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/FileOperationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/KeyStoreGenerationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/MDMAPIException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlMessageFormatException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/SyncmlOperationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WAPProvisioningException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsConfigurationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsDeviceEnrolmentException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/exceptions/WindowsOperationsException.java (83%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/AuthenticationInfo.java (86%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/BSTValidator.java (97%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ConfigInitializerContextListener.java (97%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceIDHolder.java (85%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/DeviceUtil.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorHandler.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/ErrorMessage.java (84%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/GsonMessageBodyHandler.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/Message.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/SOAPSecurityHandler.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/UsernameTokenValidator.java (97%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsAPIUtils.java (98%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/common/util/WindowsDeviceUtils.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AddTag.java (91%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Alert.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/AtomicTag.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ChallengeTag.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Credential.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/DeleteTag.java (91%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/ExecuteTag.java (91%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Get.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Item.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/MetaTag.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Replace.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Results.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SequenceTag.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Source.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Status.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlBody.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlDocument.java (88%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/SyncmlHeader.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/Target.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/WindowsOperationException.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/Constants.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/DeviceInfo.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationCode.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationReply.java (99%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/OperationUtils.java (99%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlCredentials.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlGenerator.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/operations/util/SyncmlParser.java (99%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/Operations.java (67%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Device.java (82%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/Disenrollment.java (84%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationRequest.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/OperationResponse.java (86%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/StorageEncryption.java (84%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/DisenrollmentBeanWrapper.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/beans/wrapper/EncryptBeanWrapper.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/impl/OperationsImpl.java (98%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/adminoperations/util/OperationStore.java (86%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/BSTProvider.java (87%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/beans/Credentials.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/authbst/impl/BSTProviderImpl.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/configurationmgtservice/ConfigurationMgtService.java (98%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/devicemgtservice/DeviceManagementService.java (97%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/DiscoveryService.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryRequest.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/DiscoveryResponse.java (92%) create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/impl/DiscoveryServiceImpl.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/policymgtservice/PolicyMgtService.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/SyncmlService.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/BasicOperation.java (82%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/PasscodePolicy.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Profile.java (88%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/beans/Wifi.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/impl/SyncmlServiceImpl.java (99%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/PolicyManager.java (91%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/syncml/util/SyncmlUtils.java (90%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/CertificateEnrollmentService.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/AdditionalContext.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/BinarySecurityToken.java (91%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/ContextItem.java (88%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityToken.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestSecurityTokenResponse.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/RequestedSecurityToken.java (88%) create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/impl/CertificateEnrollmentServiceImpl.java (99%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/CertificateSigningService.java (89%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/KeyStoreGenerator.java (80%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/util/MessageHandler.java (91%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/CertificateEnrollmentPolicyService.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Attributes.java (98%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CA.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CACollection.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAReferenceCollection.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURI.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CAURICollection.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateEnrollmentPolicy.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CertificateValidity.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Client.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/CryptoProviders.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/EnrollmentPermission.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Extension.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ExtensionCollection.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/FilterOIDCollection.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPolicies.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/GetPoliciesResponse.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/KeyArchivalAttributes.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OID.java (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDCollection.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/OIDReferenceCollection.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/ObjectFactory.java (97%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PolicyCollection.java (93%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/PrivateKeyAttributes.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RARequirements.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/RequestFilter.java (94%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Response.java (96%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/Revision.java (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/SupersededPolicies.java (93%) create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/impl/CertificateEnrollmentPolicyServiceImpl.java (96%) create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/resources/properties.xml rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/resources/wap-provisioning.xml (85%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/resources/wso2mdm.jks (100%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/webapp/META-INF/permissions.xml (95%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/webapp/META-INF/webapp-classloading.xml (55%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/webapp/WEB-INF/cxf-servlet.xml (92%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/webapp/WEB-INF/web.xml (69%) rename components/mobile-plugins/windows-plugin/{org.wso2.carbon.device.mgt.mobile.windows.agent => org.wso2.carbon.device.mgt.mobile.windows.api}/src/main/webapp/servicelist.css (76%) create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/pom.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/assembly/src.xml create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.hbs create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.json create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/device-detail.js create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/load-map.js create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.hbs create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.json create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.hbs create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.json create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.hbs create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.json create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/public/images/thumb.png create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/public/images/windows-icon.png create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/public/images/windows_enrollment.png create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.hbs create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.js create mode 100644 components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.json create mode 100644 features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml create mode 100644 features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties create mode 100644 features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xml create mode 100644 features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xsd create mode 100644 features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf create mode 100644 features/iot-plugins-feature/iot-base-plugin-feature/pom.xml create mode 100644 features/iot-plugins-feature/pom.xml create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/pom.xml create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/build.properties create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/conf/mobile-config.xml create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/configs/android.json create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/h2.sql create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mssql.sql create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mysql.sql create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/oracle.sql create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/postgresql.sql create mode 100644 features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/p2.inf create mode 100644 features/mobile-plugins-feature/android-plugin-feature/pom.xml create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/pom.xml create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/build.properties create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/configs/windows.json create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/h2.sql create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mssql.sql create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mysql.sql create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/oracle.sql create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/postgresql.sql create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/p2.inf create mode 100644 features/mobile-plugins-feature/windows-plugin-feature/pom.xml diff --git a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml index 27ad2fed1..fcfda42f8 100644 --- a/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml +++ b/components/iot-plugins/iot-base-plugin/org.wso2.carbon.device.mgt.iot/pom.xml @@ -1,7 +1,7 @@ + @@ -78,8 +79,6 @@ javax.xml.bind.annotation.*;resolution:=optional, javax.xml.parsers.*;resolution:=optional, javax.crypto, - javax.ws.rs.core, - javax.xml, org.apache.tomcat.util.codec.binary, org.w3c.dom;resolution:=optional, org.wso2.carbon.core;version="${carbon.kernel.version.range}", diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/pom.xml similarity index 97% rename from components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml rename to components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/pom.xml index 0da2c6395..867cac00e 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/pom.xml +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/pom.xml @@ -1,5 +1,5 @@ diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/webapp/META-INF/webapp-classloading.xml similarity index 91% rename from components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml rename to components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/webapp/META-INF/webapp-classloading.xml index 46c211bb2..185de22d4 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.agent/src/main/webapp/META-INF/webapp-classloading.xml +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -1,7 +1,7 @@ + --> + --> + + + + + android-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.android.ui + 2.1.0-SNAPSHOT + WSO2 Carbon - Mobile Android UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/assembly/src.xml b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.hbs b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.hbs new file mode 100644 index 000000000..bba71218c --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.hbs @@ -0,0 +1,174 @@ +{{#zone "device-opetations"}} +

      +
      + {{unit "mdm.unit.device.operation-bar"}} +
      +{{/zone}} + +{{#zone "device-detail-properties"}} +
      + +
      +
      + +
      + {{unit "cdmf.unit.device.details" device=device}} +
      +
      +
      Policies
      +
      + +
      +
      + No policies found +
      +
      +
      +
      + + + + + Add device specific policy +
      +
      +
      Policy Compliance
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      Device Location
      +
      +
      +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      Installed Applications
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      Operations Log
      +
      + +
      +
      + Not available yet +
      +
      +
      +
      +
      +
      +
      +
      +{{/zone}} + +{{#zone "bottomJs"}} + {{js "js/device-detail.js"}} + + {{js "js/load-map.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.js b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.js new file mode 100644 index 000000000..da9c9809f --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.js @@ -0,0 +1,66 @@ +/* + * 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("detail.js"); + var deviceType = context.uriParams.deviceType; + var deviceId = request.getParameter("id"); + + 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) { + var viewModel = {}; + var deviceInfo = device.properties.DEVICE_INFO; + if (deviceInfo != undefined && String(deviceInfo.toString()).length > 0) { + deviceInfo = parse(stringify(deviceInfo)); + viewModel.imei = device.properties.IMEI; + viewModel.model = device.properties.DEVICE_MODEL; + viewModel.vendor = device.properties.VENDOR; + viewModel.internal_memory = {}; + viewModel.external_memory = {}; + viewModel.location = { + latitude: device.properties.LATITUDE, + longitude: device.properties.LONGITUDE + }; + var info = {}; + var infoList = parse(deviceInfo); + if (infoList != null && infoList != undefined) { + for (var j = 0; j < infoList.length; j++) { + info[infoList[j].name] = infoList[j].value; + } + } + deviceInfo = info; + viewModel.BatteryLevel = deviceInfo.BATTERY_LEVEL; + viewModel.internal_memory.FreeCapacity = Math.round(deviceInfo.INTERNAL_AVAILABLE_MEMORY * 100) / 100; + viewModel.internal_memory.DeviceCapacityPercentage = Math.round(deviceInfo.INTERNAL_AVAILABLE_MEMORY + / deviceInfo.INTERNAL_TOTAL_MEMORY * 10000) / 100; + viewModel.external_memory.FreeCapacity = Math.round(deviceInfo.EXTERNAL_AVAILABLE_MEMORY * 100) / 100; + viewModel.external_memory.DeviceCapacityPercentage = Math.round(deviceInfo.EXTERNAL_AVAILABLE_MEMORY + / deviceInfo.EXTERNAL_TOTAL_MEMORY * 10000) / 100; + device.viewModel = viewModel; + } + } + + log.info(device); + var utility = require("/app/modules/utility.js").utility; + var configs = utility.getDeviceTypeConfig(deviceType); + return {"device": device, "label": configs["deviceType"]["label"]}; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.json b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/device-detail.js b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/device-detail.js new file mode 100644 index 000000000..49c3512b9 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/device-detail.js @@ -0,0 +1,77 @@ +/* + * 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 () { + var deviceId = $(".device-id"); + var deviceIdentifier = deviceId.data("deviceid"); + var deviceType = deviceId.data("type"); + var payload = [deviceIdentifier]; + var serviceUrl = "/mdm-android-agent/operation/device-info"; + invokerUtil.post(serviceUrl, payload, + function (message) { + console.log(message); + }, function (message) { + console.log(message); + }); + $(document).ready(function () { + $(".panel-body").removeClass("hidden"); + $("#loading-content").remove(); + loadApplicationsList(); + + $("#refresh-apps").click(function () { + $('#apps-spinner').removeClass('hidden'); + loadApplicationsList(); + }); + loadOperationBar(deviceType); + }); + + function loadApplicationsList() { + var applicationsList = $("#applications-list"); + var deviceListingSrc = applicationsList.attr("src"); + var deviceId = applicationsList.data("device-id"); + var deviceType = applicationsList.data("device-type"); + + $.template("application-list", deviceListingSrc, function (template) { + var serviceURL = "/devicemgt_admin/operations/" + deviceType + "/" + deviceId + "/apps"; + + var successCallback = function (data) { + data = JSON.parse(data); + $('#apps-spinner').addClass('hidden'); + var viewModel = {}; + if (data != null && data.length > 0) { + for (var i = 0; i < data.length; i++) { + data[i].name = data[i].name.replace(/[^\w\s]/gi, ' '); + data[i].name = data[i].name.replace(/[0-9]/g, ' '); + } + } + viewModel.applications = data; + viewModel.deviceType = deviceType; + if (data.length > 0) { + var content = template(viewModel); + $("#applications-list-container").html(content); + } + + }; + invokerUtil.get(serviceURL, + successCallback, function (message) { + console.log(message); + }); + }); + } + +}()); diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/load-map.js b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/load-map.js new file mode 100644 index 000000000..a2a322f8c --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.device-view/public/js/load-map.js @@ -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. + */ + +$(document).ready(function () { + if (document.getElementById('device-location')) { + loadMap(); + } +}); + +function loadMap() { + var map; + + function initialize() { + var mapOptions = { + zoom: 18 + }; + var lat = $("#device-location").data("lat"); + var long = $("#device-location").data("long"); + + if (lat != null && lat != undefined && lat != "" && long != null && long != undefined && long != "") { + $("#map-error").hide(); + $("#device-location").show(); + map = new google.maps.Map(document.getElementById('device-location'), + mapOptions); + + var pos = new google.maps.LatLng(lat, long); + var marker = new google.maps.Marker({ + position: pos, + map: map + }); + + map.setCenter(pos); + } else { + $("#device-location").hide(); + $("#map-error").show(); + } + + } + + google.maps.event.addDomListener(window, 'load', initialize); +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.hbs b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.hbs new file mode 100644 index 000000000..c4bb415a1 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.hbs @@ -0,0 +1 @@ +{{unit "mdm.unit.policy.edit"}} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.json b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-edit/policy-edit.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.hbs b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.hbs new file mode 100644 index 000000000..12cffe6bd --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.hbs @@ -0,0 +1 @@ +{{unit "mdm.unit.policy.view"}} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.json b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-view/policy-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.hbs b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.hbs new file mode 100644 index 000000000..0669d1ca6 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.hbs @@ -0,0 +1 @@ +{{unit "mdm.unit.policy.wizard"}} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.json b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.policy-wizard/policy-wizard.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/asset/android-agent.apk b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/asset/android-agent.apk new file mode 100644 index 0000000000000000000000000000000000000000..a1d4ebfdb77384606e7865434b655c5f969eb384 GIT binary patch literal 2894105 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 z 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%0DJ*Lfiqk=6NRFzI6!Tj#-_hHd*C1PX>A~hrj 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

      bpTJZwd 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

      X-kr#_8k;@kFjo^8eFn?`3|E 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

      Rb`M+skz&j_t_Y0X{ zdL}-r#Puu7Tnb@IT+z&jL|se#?Vw?DlYM3O+s7OP$B7}zxd-z23%l2$Z)y8`i_DWM znqY^2nlq~3(F(<#Y|x0)jk*PyOg8Fbd}00B(?Gu>AWoGn)$ zAfL0kC#t-f_%Kq_ERLY{Q{qTwrP2*uPanz(ZphmJk)D-Mx3BoD-?&WahoJqczI459 z*k&aPeRU0audd>4cetKiuC-IUJ32@%DgOv*)Z5vxm{PCVERA-?StV17d}`d!9kDm_ z+;s~<+M~V%FiHo1ht8T7^H&{s3=gxbEm0hWt=Z4|l|nptOWkE&H^sVp2F%qZ94=%v z3OEqU5I8C^b9~HOi0@B)is&*iRfLWnDY#;jwB!flro6@ogFV^qn|0LAKmIt7o4|lw z!}!og75lh;tGyX|!y12Nnoi>k8<>j^{<_H_%`UH^HP8I%xK2-Yy_K)F6M^UC z8DPPiU_6#UBS)seo>7;@DJkK&w!GtW6Q_O1gy#-381O#Z>bx{xHc4PH;ZwTFxkrKJXziGgCGQbzKuTKG za^f43Jx(?;)4pjjqA}jeqW9HmD89W4yG+~`@rJr(NKpk%rFGt#K4KR;-}0rKvA z#3k(Bkk@z0qH|uIpjftM3f?WVoqfJm+Kft0LIyg?<1z*oqhD}k?U6TVeC~=cO_N$J zK<%OjLjv7l$37bUh?eH0iFYbpR-omcN;{|4rpv?xW~sGj_a)tZpoh89aw@u2Z${xv zabPIt+XA+VQdbR*Vvb$5%3zr=SL+*)=j{BJU`Kp>s+)?2ytJYfl?^XE)e)|+vt=XP zYoi1y{SriS76wHWD*6eyHYzCS)ln=n6p<%5Hx4MM1W8{nf2NrmRW>@$SP#0@ z!dR&+UN4?^;%G^jS&Bol_lIviCG<|g;e0PLke{TrqU$AEvB~1d$I*crcIA8?+~w|p z8?&G52&9-}Kdw{evt=ffZk3hpU|^?(Hr!C-2GDtLshNab7>7QScYt!fe}y-@A%9R% zkrBC7=0N4sLL2L+yngQio*=>EY#~}T=XuCQ`HjQ@1fgns3+i57X(_FJP%C>7)9JF zq#w@sVs6}BSFrR(xO7pK3L*huVgqo%e>U=KB17m#opGLYa3`XWmL!-N-Yci5wz(_b z$IfV{Q=*6(8*dl%6EI7qj^N;X`MVCL5J+s5Q2cb|$p7%Y%K~SUAz&IoKg_7|1?$Pu zEbO-6jnEP|JX;f?cFJ&AVuWGy4ww{A?#S;uY~>a#XUbG91YJT@!vM2a7%riG3#kj@ zC$d1~)#XbCtRnzMIX5`i|FQiTd4!w-!@X%SuYLza{|hg6M15Z$Gl;u?7csEcf6F5J z5620zp;1qrET@BULc(JDtbIz_!FIc_?8K4A{pJ5+B%^+x4BqT;VJaB+9B6pwd!`0 zrEKF)bN*K6QY7Mtlhp923Tjo7>j}VfSgK12dmm9B`};3cW;ImJEWA{k_rvQ_LxQ)P zd#66jTVAL-}Z3RE4(pNsTs<_)DW0cJG1DtQgr#w(L{v^pv{;-i7ta_bN8A{CEb zy;?2RiO|twelGF6v&W<>mZESAqrH23=X>iLrkqb@j7?kqw5cd-wiw<%Ecf%)TsPjv z6Jx3mZv3kiAEht6<7tT;+|UyG+4NNFkq>>czb#hgd${G{!XYlXaa71C#`}2zAbf#N z;mj1vdm57IxTycwI*;XRVX^6LcFzunH1>kX@3AEIVEOThEs2B1({Ig(-TG?D2jgVQ z$ov7pL75Ik=kbT}ZydwE67e{(=`dSJ&N927VFn8u61g+wY)pRLWFvjF zIKA_%GmcFm!|l)KdFcnow-oQ* za=4*$^Kcvl#yDaRQW&G3mAoKH4*I@lFEAYEBj24?!&tua0eCO(ElUC`Twk;l(t~1s zvD&NKiv09-lDmk10Yp~?5l9EN$?OV!zvk%DB!rk=l#I!~wKC~3f$8{quyw|S%~tZ# z^qEL39`eRSY)JvORkWIEH+^)G!tsEKT!h-ohl;`Z6gpM7AY>i_%!Pt@AUxAM8A_FM zn8Ogu?>Rq`J&9xU4t>pE$rqr{=BgaSiubaoj_`i&g4d$=@w=K{e80i_HKJl!^yyu* z&w;N3xwoq~pc*Xmm4H>j;u{TG#z;7sAY4ka21k8?@#i;JL0AOrP~AFiVb3Z;o$&~i zqpTsTq;MwWYyO4k-I~)eWh)9l3B&!Uw0l3I%!rm-KIp93ie^+K)BP&`0$wsTRzG@B zFYc6V57H6(SlL`^ib1t*NQNgJ!jS(%0vYMZYcK5j7C z-N_>Wm|ySNVKNVBy^ny1@xd-)bW=2RlTfMGI$3YY=DCKlyQj{RUUm&oh{xKj{>-uv z?(~&4@7Hm`vGhMPnsdY95^mz23ZX-CIA?C@|8)GSybGBQLMbo3>=$*^)|3=xYF>h~ zWx2U2GT(RJ6p==zuiZ?I`_xX&!m&rZ>Uk==8Iio&743GU3Q75ES5yLQ6_)J?!lOsz z2_B2$&slV)wMso4`z3Kk@1(xN>*LSz)#r3H>1RjY8h@L^lnS1%6kO&OMoSG(IBW)m$;C#idgX*LfMa?nvFoU0*T& zc(ObyJXgiWVz*AKqZ>{x66kQA!Biva^d0g#p7R)5=<47{e7dJ?JO9kR8OeWt_bWbI zx0XJSg@h=_;|)nfu5I2fzY6VTWNgq#>p2m!GQYa(p$8Ocue7ExB5hxf3;6DEKvjGD zG&&z9i_r?tnGmm@3zLd!!!URIO4YwAq*B!2~ zSMMG2JUoh@j9zF)54lIXhzk6$Skw7JNH-jpUd~v-CZ_JMt<;VhCTTy(w|R zmp8H8Xh>2G#&-?5Wkir#eu}PreHs7wVp;!q!*gOyaJ~uHH`v86ee-vmm>kg$&S}?{hDg)Dt!kP z=peqq`U8b4j6VWhIBR||#OaqHK>QadoSzJ*;1bMA`MZb#F#kOiZtvi1XKed7te^i^ zF$r@LzrpUQh>R0h{jb@;9~Tt`|0v-1_$v+vkNs}{KK{4I{=VNI@BL9rLTMjB8~D&4 zINZyYbds#6-DUV-&)e^FTsKt&m9j}DVFK4&_NF1 zEt6)#OP*6L4bzdq!hl3uD> zxI@1M1{DkKhX9=Sx!oYA9u>fW?EpBr{%gZ=Lyolx0Zi-rD&XnFrY7QB;qLSd(f)`?i7ov$0*}z&@yucOt6MhFcE*#9@r|*ANJ~!GB#bhqiTaG(i z3hm0jr@Y~0EaGgs2%<%`2s%l2*m1s^6QZ07l_CP?JeG3&$pr+02@(XfAw8!f zDePe)E}CccgY zw4o2udHVt)*DG;nWh-l$!99x^f*~5GJI6kyY=3LD_m)e(SM!IY*S4;Q!Cp6>?ziMo z&z3JKRHanJslrFZ0$92t74Snhr*Hi}8r*Uw39_ZmoJ>nX`D~w{iPd1mmvelLO)YOB z*f4C4gY?QObg~}3J*oXN8iBe=u+de(8At9atCj#)eau+de6!3a3 zB?QR4Tfx9}%>{qIK+|SJISryfJt7W<=D`qEJXY2&sBP|iK{gab*I9Rm@@L}L zH7u}!IOKs|ztT_uhJMw`OpI6p3Hbwq0UNQS42Sg^uM@`T1HbEU>Y}O^gYrE3TCo^k z?7HgPgVqsB7A>|jo+mB05)wc4IOJ)2QD1pTB_$VV^=$tCo)g?7|iUzPSxG zd?x!p?7an49nH2bx^NF`0YQU%AXsqM;10pvAy{yi;K41p1`V#k3GN!)gS)%k&ffb! z_uuF2_ukp>-7)SR{N_60QZCERX^Q zNJ^HgZ_FRB4Rko8l%@(ehy`h5`H0CHFB!)YYlJL5Nbwx%Ekl_&qkP3fBk8n1NkKPs zdgD1b|HF!Z7RMd3aB4X&&$V?S&NU(}uC|yK@5*rPJP^tY+uK=f2iZuT5wvcF@^3?J zZbQw2O)C)wILa_59Rik}R^I*UiYd8#t{fi;K{|IOnUW_yL_vb-CvvecA{&Rm=|jTu ztvyUY?@uFqYkml30s0-IXC9_2mprJG}sfwi%?RI947sur0E@G+d7%EMFg-~-pB9c7GJ8hA5 z)hkc(Gp{*gkn@=dHEB>oCGfm9q-p&8Kl)!<`*3W7#cAsyTNY zQbd7AanzQJS9{X}P);@|B;l=L^PYULJ|MZEqER|_%=g7eI zB)uCzVUo{uq_phFqdUe0W&I*p@t^p~o#K_jAK90nPWvvQ(*{W$>+*LOTb zTyn~W;SDqDh3q_iqEjn^F{f^9=xjVl!HmO?AWjCNgD`$6*&t9$Kl7?uhpgII8Ja|y zYS4r2MA!Q4sh@JwB85qc3NIA{1UNwaHnRje?ntF(O#6lw;Tz&|L~mYuX-4GhRViSk zUOb}3M9b!-dmiy&wc35OW9P__pJYigL%P(Ihv!EBWv;f1?`2v@uHd&;w(BH=mfwvSTtBwIS zw0G?K^QFYAJ$PnJvGEEqHI$rqlG`VwE@x}$gbb^_31SLXwAT4=B(UEMt~11bZ74>o z)4v?%e8DLObv&;0t}rG+qi<4*+sP5kyLIXSX*xcB-LrI)tQ* zoWd&Yo^7odoGpV2f@$vpP{E%Pf)*fsffaV|aY>M1Tma{b`H6{-M~_b)*8Zzo6hACY8m0kQV)AOKwTZ;7`50jmFG>igf8Z38>_L4OXv?R2T89}7TK z97;tskHq70G{i_ttD&f%aDoBCWYdsQ+S}j1)^2nx@*GTjgGQd-Cr&`i!{ec-tGhf8 zkQ!4%Rs5`Dmi%JEwR-CM0D1=t9?sI1larf^r&Uf=Uhk!3XJoW>v$3(k1KF^GaD_uc z4R9mpS#9i7@{@BKZVN$@E}0*hEUjmIpEjr>Lkk!A$aQK2Z{eodG>i!+o$)i z(>k3#J$9i^x`Jlv8ecQIr920dv2{m-CtFFNn7%bT6Do?hpN=8WqmxP<<#Po8lJUENyJM2uU9<7#%V5M>c63kdk_P0WR_uJqd}4@);owv<#X{BVQHYRdr!o&=oaoHReb z_}Z9)(CRrS#q^$Z&t-`~H^^$3yYn~e|kScf}mj|ewKl=A8Nm( z!=Rd`Av*&)getETu0#$}q+ntsf1IJN~%X5TP)6*q1~iIp)>+y$6E)xgFJEW(Na~>EqhVSRvy%JMF`x zFh(Eeh97f;J*l5K6hY+f=%3-jyA3&szPl1BOeOWMDJ`xlEyf7+Si)^fWrNAeg5vR1(s`Qs%A6+CD;9eMu(Z|${fg^&n~zZxSrES)H4h@_E12ntM`W!f1y4!C-l|iVa!7CIwz+ZKic4z0zCd$+a$F6b;`-(bDq`4Qe$(zX7`h}bma3cP>?3x?`?Ba!~Vh}cP=zlY=7Sfu5-%+ zhi!{o2SWK8fWOS=$j}&KItSVXLm4IWjBbKElNFjrtl) zi#Y2IKYCj~{QTr+pdDgtzB7({;s&=TnGB&bTf>zdyZXklrrrpBbli%})F}{Ro}3c3 zc>Qz{J$vHZ<%U=OJjBTZ=LcOOlOEZ=`P$s81=5=^^5R1ERj}8%p?bb70_VECK?yYd zZI6>FMwp|;fyhWM1ESzrij#!bZLNWT^08Bn+k$D$gD0J1TU29~IGM0uJXl2@;ldZO zbOwbFjM$WHK!i&zg{WlB_F(qfK(B^#ZGL?Hh2Uk4h)pxn>7oS

      ^9sJuMkvxGNPA|xRxYgQ_++^~XNu9lA_0)pR8BEo_HNICdrBy%nI8$JJf1nWrSAxje!@CQ>M@_2)sH!J)+ls z<`hGSs%^snhw(kkknAsk($O9F_yuMuc>BS5=}?fZ**lTCMXs#PF<$!kqvJ?*nI9Ot zHPG@nWatVT08P;cR;s3^bj+xR`wAfoZ^mBA+a;+&`QtFbrg_^*=iCEH!7}c>I;16% z)9W9J&DM{M9?PGg_(EApDB05T*w0>;7zX1r?mB!fXjBpmm;;?MU};E1P5MdbdKvCh z%qr9PAr3T_LiC$$bq7wDn{$u2HSEPi2)wf?)t*0%iSX<@idx}~0)>Bkc<-9dV`12H zby*>aeq>kXH5GW5^*=Ux{Yi>MrXERRfCnzi6um?5%;_MeN55>ub@uEtb!S_B|BAFB zVt^+fJnxMrGP{JgiAT;);FY8L>i)8Qmkobl*W5-0*I{yECE# z;|Uc3niV!-vp0=!p(ycmj*j(tJtSqcil?upnZqF&Ey$!JksY>D_#9G%6I^Ff;SS_3Dl-DS1W5ZxgxX-#1pd-pIo}pjXp|O zPbsWqJ^604u@{}Ca$G2~rbG%3KBVC>|H;i&BYLpBv#VCklNX*wYYSsAjm=tHtH=)- zJXd-29y`4vUWAGhdo298w2rO4&spBfI)|Upw!uhpmrX5ENP+vD7x9jfO%8 zm6B(6-3?{?*wW0f-8B|oM$$VVcunMWnWEiI!R)YuzKPlHWA=7&=1H3`No=>+)`-D* zyc*~${ECJ?LtRuEfh_$BuV~fW|Kg4?&72AM3-gy28(svX){~$KtzQre70P&UsJ8Hc zMI0KG7-66=>nEd$tWL`$Q?}>B;_S0D0iU1cGv=cy9rl~e6L!m8uMCBg)aaWXX^1bM zuU}~lv`4XU)wJ#@85@1g*1=?*eDu%K($jb@j0eP8U{mFMA2T`_I&o8=I-=vL)7B5D zFU&XMi6v=Qhp5%^efHu|?o+#=lQ0;At{bVLj?#~l{*UF z<516wh4D>wcW*O0tqXd^V&6bPpvD$BC)KYo{veZXe_dIl&>EW?`DRY*=f?VZ-RY!Zn;&dqlQmdN{tkkK z4jPRPs@BFUvEp!bnHGHrGuk00;ZoEX;@hbhOE)#}WWneiSb5p@1mmwbrx5fcYjA24 zVhv2d5JuV{c=*&+j^CH;AkcM&)N6|LY2AS`-1kM6IqXYaeSM+@sbj{hWV*4Y#G}im za4;gCyOj8SM77KL;&t-};tMvWz!jNIic(p~3as9H8X>bTDQun?f|uV9_R!uw_geXo zsmAFuyW$*e>qd@(QF)PWHh4d z&#wxqf#>{!BO&Tmt82$`;B-B3xF8A2H3C9QMbqK3e@cU($Be%=5XoY?zK8DRW~~lk zSkkT0imnL(Ii~{92#An=VkOwCqq1p)4{;V$>gJ-i^VpO07-06p2eCxN&4U*Th13=+ zzE=Vb!n2oGmbcou^L1tag0U?}vRtJwE2ihAq^0qw2a(*F9^07DskLjI#wipb2NMw! zd`VaXV*_cz8$+(Tv=EIfoHn#{WKoPOr1j$$ldd~He!PcT7y5y<#!sicL@6Tz;=xXn z^qr_mjYONZUbU{((5ng=^qh5ENHWw1;oDbN&#z5ImX>|Nh|B9uHc!EVJ$5IH?bTQQ zQ1EFJnLG;hbn(?)FUp5g`TGY9`=jGk%7w$nyC>Hg0t2ic1i&rWE;8Gpp|Q^5lrfCs z_R}jDdq~J;H#L(95yPjtntyv{s~XtorEomBEHEW*oO!P(`=g$*7=XmG)8Y<4F|C7h zHp7zP9Jhb*p<}p#BQn?LRV#Ifs@J=Qs%@eNdT0d33w*bcqeIvObh69BG6WB7Vmq(Y zw@cksvzCbBkfo2cu9d&m+9;cd%7J|HNz%2Fc9c>py{lZQ(Qfz>>sf40Jo@P=$`-ff zF<-qw9CKN;4$qp19^Gjh93_?W$}K|CwWmt0(;dS%54P?q?{kwsWtb`ooT|5GoHel% z5^Cl(EA#%ww$X29omwpak}avB_S)ptu~vpGHOJRxQ1YJ5JZ5vNiIyTrpOdRRaD zc`zh%-^OxKQ_;DPeo4A^A+ieeXB4A!<%qb8L5P{pf#DW7At*>of4Du)ZiL$hb@`Jo zltn~D{H*VOc+qb>o`uR~{5A~Z$I$(9biQkmeQex6CY{qFb-fBcUYQs7r3~|r_e&M{ z6O+p`6Yie_tNA$TlSlJ!MxVck$q|$N8%*?hYRGT0hGBsi+!z*oC6|blz3-Mwey?dUS3N72QVVL|CsB z(_MJTOd2qyS=++Dgd@AlH|bfIQ>gT%v}bC&bmDGMx|B1j%Wa z;&v(k){^K2&f*Ya?VI`UJQRJmviXi@p}gGffMu=6A%l%iPKyamCAOr=dHIb5yp_JC z%1VRE%laP4%FUIL*e=B5A8i6emKiED)tuy)*==Y?!iiafGzG*sGpzHe#Da`M<2=-_ zjp@AzSOu>B@JHD76MJ3`c<|-GC7rWq)-G^*mkp35JFgK1YN*5kce*?TmJ3SbwQERO zScpD_HE;&q4N`8zo+FKZYmWRtbM5=XxJseuqI1k&Nk$WW(sc;Rldn-)vkWaJe)t>< z-L2-CzVkIFm9k1wbwG!$@<*flyv)4cSQG}6FmU~VRV>oXF0o&xq6q0l@!(8Z;@bF? zvpllX@C^4ZYff?%NgT4!g(l%?KbkMnra`uJ!4@fL(~LW)Hu|(2>Evj+d4d_F8&nx0 zTU3R#d7qds#U^mq_3ckOrV%YxK&BJuuqqi!9(mw+#3@YFCeS9o1n2eXHuGbkG+L!4 zO*)5N7NY&l0ZJ4;pVl^-)pr%BhW#30S*b$g5M?o|_L%mnEY}aF@8_vK=xNARtS6jm zm5UYKjdlJ<(^U?5H>r9c@N|D<;>m)!Bbj$W(wR>Vay|+*V@c26Mj?iNT}M^YZH8)v=MDVDE*F!!R8g+H|2-LcDU=vkzRC0XZ#$E zHhHj0Wt?%D>Ko2CB{YX=QTbd|Z^rBSF^#}dJkzhlBI>$K8UnZy8%Yyjm{r<{SM%q^ zax>^a{wB%mD}nG-Mn&OHngv}ozWQiHCS~+l*Uz=5*Tngy3GTrYh@rR5^LxST3Fw|aS=g6ACq!n6t);+j*3xiY$?gW>2K)n zM#J~%OYFajj;|bBH#*ngE{T|!on5PM;|@Q=Pe=}pi)-TYA$(uYbmgBtIO!K9F?82#pDyNAG^WMiC&}g6wS5RlnGkm%`B^VzZe2^&BJ?3#W ztI%mw1_O$5I7K`>JbW`fgx*kKS|72}vV}3y@0+Rb(Q?P6u)|Fxf2k+6X)EdBoS-z- z#U0?>r02)W+FobzLm9F>FO_S@kDp30O>IyDm$I;V?$j2)M&D8v_%d-?n{A;N!6Qlh zg}|y^NQH`D&$(Xt-GA3Y-Xsxn^tYY9$fY&}1*+A;@aA3BE_E8gC}o}&s$^B`MN2U$ z*JCGBbq6mnD)sA#uqu?#EAI~uW+%8O^ajTUdqGr-vJHl8^UJ3=9p`S;=Zqw^ANyIj zulAP7#DZHXOx0^y-)3v6fxEcZd=w$)iGd$8J_j;hqT%nKg0Gz%!&fL7!?|LU?W4Fd z2&pj8O!7A?I>!mq>V-Mto zlf{3&?VcH#0xHM(c>XkLAp5&#rm476O)WA)cGm9zr@9)lU(aHx4Yg&0o`Qz@QNMku zB)&Vuis;QSUOakryxuLV9L<(qJ6rCWnwjxmzrZtOKuy*t8AE@>y3oOXCS<=lBBUsW zPr_jNU~!smBx~gh$CN!|U*{d(3&rU%`uns`+##>=Y6|vyZXmareci%~mwaGAmOQw` zhm_}TDnBJ0orgB%^52)UoSPZQTp=o+%h}59bDWKDkL-_HtIUcsFfYD}-jqRNjCwKz z-xb9jKY#ilWHOw|cZ!#4hjC0Bw(~Kn%V)skx;UupW`O5;%#secc>mHKBhTl2&Ub&) zx}W87j|I$ub{AL*T$cY%5oDO}DoaymS-v#z}2*Z6qt{8-t#PSb2m>C)V>S+D#X{-c&4n|2c z@DD!I_D1E!j$0AeojoJnab%y5qYuL4ZwT%4dS>-AdnlJUw3fZg1F@lK!j(_I&XOl5 z4Sd!FI-U=WHFPy{qS7`%C-%pWa=ucBn=03}YBjqLz=hdpwtM7Q4rnB%y|;T9x9`uo zl5VlbR5lXhKZ)kUqxs>x-ETem>q^5OP?3xL6u)?O5@h=`yyX+0)xVV%XN^AGcfWT| zHOY>ah;*F0V&7yqr^rxz-YWdf_0qCV_*L379Qdfh$u~4a>nzk0l&+&3Hq&8RA7}Ev z3YcwP^Hi%#$w?UwCs5TxBjL}cD|dO%vX0p<===1ISTArd|7u>l+Yj)1x@k?UgF?I6 z+ClCK+dUX?{oonR*E;RkO%R5iKCvn4A@@71RWCBWIz15eL}{9PlS^JVw1&Tv z_bu=JHBJU;h-W?D@@u=kH9S?5ccZ;giH~!3r|sp_@}hFdg^~H`v&>rl{$R$tOxzSh z)(UYULV}DLMj5W*GC;$j}`Q zc5&R8wa{Dkz^QhjHF@`BsBkf2Zta=w<>HjPXbTY_P=!T6ASmd6c$$&8T1Dx_Dp;;d z<>7p$1%8ci^C+8cOEDc43F+4Q&?i=U`7Um&*^(LNLRg<(7mxL}*t-ebmpAW;F2XJ4 zk^3v#vF^zHcH4$#dik4sTs}S0xrdU7@y1lEfFIL4^I|r;vAW|lVyi3#yR}|}Bs?*i z&l!R4W9J%-o5qwFhSlhi%r?tHzox4X{-6qB8L#4 zariDa*1NxNKEBU`EM^bBn#sQ3R7odNcdGQODfGg%>YQ+=t~oafyUlwnJ8b1+wx^kw zKWkS=Jn1e}$c8fI*6R$+qV~MEdR>AjL+`?Ks-VSYXX&(t3IkVC}W@c7&rL9oA|) z9(a+yAWdcZ8XjYA^Ss%;$<$epP&Y<3GQ`Kq%Dp{h;}+c*!{w?T%jK%-_|{omHrm<_ zEah>do#l0-xZk28Jip&h+-+vwx20`=Ia3F)d^*=?oZEw?`O0NLF@)D_MoMHvOqwod zo?*AcG{zV}kMBXjbhb^BYUb@an_^*iq+G2tSf|x-uD-ZFTfs>xQF$IHXhkh*z5Cmu z%-b}fT!spD*arKpzfiUsla3|NP1kfjD>u(7|Cm}d3)_+c$>uqvWUWA*i>xrtqo%ph z^iuWij39luV%3s4qY{41?#E6;c4EU`dO|RsS?Eqfw2ryB+h#rOvHzU)yiS+r;?>>p zLUnbs`9#){M3mVhnwVmvbmEFuqxGrXTE}D2O%tHPKQ)^=^891D4J9{Ae`@vr!F5kT zad9dsTu%LgQFz=dJ?8`qj>LX%j2GFTXru5mBwy=SZK}S#OxZ(^b4x>ws1zo!6(oFH zO+QcSWrtSVZT7dp*><|igQgEw0 ztn}-=qDjig$mmLTIW+^H-ba!K8nIWumQN6(ACka>c1&(^j}dd z3gBJ;JBp=mV(4i7m&f|cWBui^{_qX)tiL?g zUmoi(kM)o1S> zm&f|cWBui^{_iKa0rnlp9b?K_T z;V3F#`>XEV^w?Qp#;&W?X-?9Pjo!=4%fAl@lvo2+wzjtZy$RG6JUu=A_d3f;QZ{gg z%+AX4Dj>#~o_9jU3*bclx5s48`^LKg^8355eaG7UHBeK};2#E9qwjZ$rAHnk@<4un zlRrkBJ!v4{idd!1>E&zpiafYlo+N?c)k(+Y&ilw`*4O_)~^zF)~5RjgGv_qe#LZS5G|M@^y*7dKKY|k z&|SC)`F%282)~G27+&8uC=8_qhy<7qTpH~bH&`F-cVH3U1 z*w3d4eew+WE*P}4_iMc#_0(06VwI8K#~S*9(>P)1KV&S$MS(6`AK9T57vb}oU`~wY zUiCdyic+`13j!rte9OF?5|bk>SaZh970EB)Fgp-x!3*q9|wpnHB+raPQG~hl)_o~?p%E)RRSy9#!4^- z*MI@BPa&Yk=(`tAg3_ZzAO+T02S8uNSLI|8c{=smk&Zl?AFMvQm%Oq0+O~<{$kd2B z#3H(L9~_E>%^Y4Cj+~ztnPxCsr<3BmBDdV$#uFUISd>%NT;}J23=>Vnv4|JswSUit5I0*F5!VZG?U+BvJ z$IVVQhF`z_7c&F94^xzvK>UCMOiKwul#&!x2A(B>h5BE9ra(F+1vbq7M?V8*1`G_i z2e2GqKfs@WR{`Gw9tP|Rco=Xp;A+5}fRh1}1NH`d4w(7%=K5yf=SgZbVDJBIrCT{2821K<=||UICaI21ruck#k0nM5$hA0)$k`IojZ;%7YQYA!DRY8gNLRh z%c29^5nSD1gR1_(d%iz-BH%E(yV#_TlJ6cr@82zdl+G-o5%KB1392lCB-MTF5_+nvu`)D_N+>`u6vx>^ccYTrQ!_1D z&-S&|&TZZD7ZQaSRg$%#{*)(r3IXIYlTjKoRa%Q)txoaoS`f4{VdfekLjEUuJ8y#k)_+ zo~k_+9uG3^wzc8ubj)fI@?V<8+foVyHX{E= z&HhJ>0Lq>M+S=dW2f`5WA}~KG5S0KG|DRy=FChbJ1w;yH8BjDJXF$S$mI0anXW0S* z2eiL!p}D5Ox8rDXR+0?}d_TZtLsN3k%N}qEuzy9iStj7b82%+~#hi`z8UsP!e~CNh zf06hT<_d zEY$Xm)*_~@a0AI@4{Lo|)nZGf!tU}I?HHqu_UkBPY^FDAwjB4J(6xUnQb zNzRf*3={EKSBA=F1LP?Ald-K_1nKF1Nbsd;hpP7D(U>Xu#D!2+@#@lv-@2gir{&dc z)m2qT&`~g$r&pPeui@QI))G%zB)7%(QU=eM z$}dL08xtkoLuwE2Z^xU|--@@X^P&b^XqtoJ2v*brzAj~ z|ATqku)h8x2aNmA!Uh8S|6yL||0de}H@^MnnE%cl>ow{%fDOO@58wXVz5o9CpHoR7 zhdequ0#dzy=am0`1CaIs*8O+H0o)7t76?rLq?q!&fMWp<1Fi;q3m6^0`E^C9JPlGZzpX~k5!ctGdTIpEE5$LXK4BZ$*%J>}WOc;6vNu0uB1 zXAM?kB@A{aSs|)xXf#Bqgvd7a_iCZW^%@yGAtfEVdy`;-|L_p{Ugb+-@Ti1E;f;eR z`i%gCLgsM*CT`yma-BHk1X8le-`*`-^6IIzWOVL+c%m8$=Lb!USwfl8%7F7*zo15z zUt-AS7#B?uN)5A9oCadGL?wA3LS*5)m!Wc=fz&oc3)8-Z#?nxb-y9}Ue-E{Y@uG5{ zOER!pmhoaiD37Z+j9gQe62sm<%n6A>bBlo|IZkH7FV#&E8Sp#&CSh6R#AfvAfGR56KvvaU&85(sb(Hl zw<|!uK4I43!fQBi=#GJTmVawW_UgyUg`T40-kItQGE?}Q)bwNuyU^ZfY>}P_@86|Rt zlNj7bK@hXY*o?`VAID6S1Uys;SQJ({F#xUoH_rQKmhc1^n<^_HBl~ChCl~u4hS4~h z+M60W>l>N>_kA=lbl^|DV1Z;21fgTV{-0_Z>$-Y=`Hhjj_e-$$x1jr z3aXS^LrDlliS}S3xRZmH6%33joLEvKb~3#|u|Ni%t#f77`ucf0(PKebQgC(|slVN| z`t)pceALykK6nmay7lxeWC`O)|W3UleN8YKTVf8}R_W0EO&=$>m zf|~k*gtEa<2#^XNkku;qaOX+|{>0|+JAJFjZgQAZl(dz2ji(sCN14EgSTMi^=8z3jd|vEq0#L>-d+i28Jx##Ulg18ndO_eV|DVAVni_QG5|T ziV6}EBkO+EL3~Sc(E0IGH1MfKsnmHO#73=3tMg!hV4*^bt}Ua3u!h!pmnr)?EHso< zN*S%txOlvIZK?X*mxrXcuM*+WZa2?*LO?VoJLy^4t3kqj2wK^uS#D!#EqX!p;k${y zyQjz-hbvQ5T~zYDh-LK(hRdAP;-fb%+jAVfp`K#w)`EhZam+(?0v_;j)?Un z#%8P}&P?w3Q_=(u2}{QF>V}0kt0aIFG zgwhlm8&Qm^>Q;M7@8^X)D#aU4oGD_QE`W_4cJ&;rmqh{duX_&ZfQw8()m99>kfc6^ z_=JoDVakkdHGsn9xVz^wFQaoMV0==e;rZ!euyyttiH|eyTfLdUXf_3`{}8Vl&0q*( zg+9vEuvlzttTwxCi^pV7)G2EGg53iquGm7FkF!jIoj|Vd?es5usiQ6md~!`=l&%iM!_HoYErV>>5DkzNKz(}m3^Bw zMo6fdB|%3nl$-HwhCl&HQH=AW$Ukg1Q{2_Bo)9CC*d87S2uMZ}E}Q*d zELW|-HM^e%iI2(Hwf}62z@RQSdEKwxk1oGiV;ypDz_ei#R(%&);l!H)TV0YO*zctTNuj$$^C=tj^xiyZs2RC7C*Sir{02n^Xw~3t93t z>qv_kOjF(mj2ONd49t%wxl$vViU6s}9t0Yy)Z@-8zz1mudYjYe2?`2&ZtFF*lcU3% z&y>6X6Afqc9Ba3)o{^|}^2^i_muXZ1SDmh+!r7GsRas840%zzwtfCxGX5DZ_zy}^! zQf_n0%GSO#pXHJL0KD_g7TSBeMF6rl-R;ssatq1T0V9l+Zdzlo4Y=g`>K|5n7Xn`(Z&W*f#HLPQk#_6Y?A z6@SdtBh8MDwZ|$iRQYOQ%Pu=6@hIY+LJ9%*f6z<%A}k?^?#be~!H=ERCg5DCCAr>Ih0n zROQsusPokHT;={bT88`%`Kt&7(pg7PlK;x_1x>edU=VBIL4Y^Z=`eyEEXR5nw0lEe z-aw?;AixOjLoy4{LI|WSkZ6&E;~Rr*;kk&9hIyyiH}#IqV`P6N0RR}AZqU2746CR zzSp*sHAc<%Cr~P)Wg`wKNN)}WV#R=EUK`(zx33viDq}V7W_DHhSRBqDVOSSFbC}U= zZ>Ve}L38>l(t5zXVTW((tMFN>>;S5jxDr@D!4` zf{sKh76 z-n&PnpGu&0s;Y$oD_VAfz<)(qUYnShkT;$iFh?Ujwuu&cWu`GleZn)k3Do^y=( z9vu4B6BFSFD}t@a;5EDDD(2Hq<;mik^w8sOaP2@_2ki$@{*I3sslQ>o;lCM2iRFuNXp6o} zoxkB@r4cB0`7nJfM>?a(*@mU-wgN_o@(5x3f)N&*Y}(O@kuDWBOio*t_werm5dmS~gCUqqGcN zkAzrB*`2+-!PK`rl}`j5LvTRi+ppC?NEBaKus-}Zlt)I;4P`mE9daJ~d;zieuqJ#w zefNBOxQrOV01fER*QR!8Bq=#Qg5K&MLe8EcD1=;mNAY`YgNGLc5}wZY>ouIpOCct14aHOD|Moa3>G8cKF{r`S0Qu?W zWS7MMO>^sj`x?ogFRgq*v)=QD3=s^a@K#?N^R_&h7iTB!1*)ziq^!fxChjT`f+keD zg!U-3-f_p(anEAMv_w-feAE@E5XOt7Y##}1#A6EU6RI|9emT1N&?FD6=+}I26ua!5 zC4LY-Y9M$xUZg_TyW!?mwm0h(`%Ho>D$8qBoybVG6H0z7#$W=O8hSE;&Iw+AF7a){RiFax@FuaTjF^3n0MTK2d=f0IFk zugNdxS2_+d<#mInqlY4{Kdh$S(u-W!zLd5Rwq>8m4rD;rH|)@i9`>_hYeCVS;oCh_ zNKlj3OgSVID^Y)l2Q2TPRt}1_i~QMxc~;}%SAI{jveAgQ+EWtx^1+nPsNcUJD2+8^ zfjS_Nd+^6N&Je}GJdsf-!>`nCLl`Amd}b%=$ONjjlRx*ahZ`^=6MmrPGT7knu&e4ot`i^dz`2eLW*njRYoAsR-UyN#r9nEW1wak*oO>ETRjJ{7M`$}e3FS4AK7NZPGusO;MdvtCuN$3z8ynIF!!oYXUvL9i2 zV*GS@ichLZn-SprfRsmMH-v|9X}Hn(o04|)?O{;K((a7HBydyyHqg>PD`LL56NUN%brveqKC?qESD132el) z_(7;lNBju{hrM@%fAomSo3TPV2?2vdr(O5w6NVrtr|gIiuM9DQM^$4W^ZE9k3`uOWe!Cp6aa|Qt8F{FgG)& zU#q;$VWS(5w6O3Y@ZY9hTZda;)mx#_$z3W8zZ&BcoZ55J3W9?R{=Q?%uAk2>M|S=>V9P0Q;B#M`tpvVx(s6m}0<1DUlc zM|r{6wr|jyA3GvYgny2+9|e$;%7H+#w`zo~5vP36X5^d&a|8*359qzZp$~@=1R@f^mR>aJV(HSdli4BN~k(^Pfw9c)lI-pq_EQk z5};B0J2T({=5P@8kd%H--7SoapZY_g!kR{YEo-@LQWJFi5o0E?G*svM&GR`#QuQ0E zaA6mtND}J2ZyduvsAUxqLi0UYfz?zfqXr&792|?vdZGHk9#Qi zg`cJszf6S+y7p&QYuA7JZcc@=dZwR5kGKgFl=g5il_k_jN(~~6dDnq)Qy<;PBBoOA zKapDA&y^3d5Qn&+g9c~z41p0sq4Ssm`3k}&v&+-7e-{M#Zk?kN(e^3|MQ)G`Q8{Cu zE>=NgVL{Pv+A6DNs36Gz>9J$=~C|@uMOCyKdinotF+g6R4UBhKydpgNhWJC!n z9-!XblPas`ZuhAzkMZ3riHc)ZCZ^ZzTBYZbihbuH?9mA#SQSk|hoYTw_&hL{$#S2K z{_(zf*GGhq|I#o<>^w!rw+7bXwSX9&fOU?^ZJCyN)ianQo-{e;ff5 za=OV4f4Sm-64tlDw5fK#_ZOva`2tjL9^Gj4UO)@`J+mPS^t4=CIzB8`Ki4tJ!suqs zps3t(&NdxVU)8>IdCJ))r-#Yu)Twy$Ix;%n$;tTl5a}3BwZF zJV9ftA;AjsouoxpMkS_OI8V5GN01hiWqeUj-&utpvQ`kie8FK3JNcK_@X-#q9{I{svr~px{Z%qh5to{AYl^jEWw&XOq?w2IuBOz{kQ*T4JKz{;v!oL?R#^{#EuLl@@&Qm z>nZqgq@|fu-F`)^pGCi2Lv5BC7SHS-cBoq#9kWyn$0&aiv$@i*zjDPVCX#g1V4I^T zE%B~~dtShal!i*eqU2$i4X;cw_L5O$RZ1ZAUB3X+tB9hP=xLGt46Us^81BF63So(a}OY{R#jgSOIaS!`( z$K|{dLlPwXi~^nb{5t@rH}d=~qw*LlE~9N$_=lXNFKxM5*2H^VHqcFIbL{;iYt?~{ z5z7w;id(2chXkY5t8 z^V4|xu7iYvLmQ{6#%-L-^#ydxkpPXPlkH!VTy21eji>3Xe(%Z?Q6DzKw zsT|$1H()8mtKC&Iu?^^B&8_)@!X7>%`R>7jLyQQ6YqvB!;{IRky=72b-PSeQxP<^A z!QEX#fCOkDxD(vng1c*Qx8NGw-Q8UpCurmD?tGndzH{n%?t9+1zFYU+f0yc_siJr9 zy~h}9?zz^SYfkH184^2K5;E6E3;uBfy6=1vGUd;RBguH`y%&rKZuj(v82rn;;2eh! z=rH+NTM(;s{T0!tlXD+Nz~$?FcE}p0LWAU82||*@c`jW7r;scV-#L@`s zuG8Zog(PeOBG9@3>%!@JSbTT%@e*uWboA0C z$QfYS{<+b*0&awgteB9Ac4x=GyWxyA_P6azsOBJAh{jMjH7!2HdRU?lGgRQKp4lPv;v;pp{UN`B>E%MSBsn`y-L z1(>O=9|iy@HInbYWHd0W2M4pCXTPyn=Owlew_LZ_^!iRyyJ1a?FL#^|72x(Jt82t# z$sLKI%I1NG&SI9zVmt8VHAy0ZPPr)GO%RS@BtsS`E0oBjgL~PVqz!bREtD@4kh1vc zc5S9yF3;3#A#msqDSWkdSV5i6Wj`0X^2`|C`}|CX9#gdJA5m1kqj>>~NkUo;S$S9< zgMpd-&f*kH8j4SKn2hUKh7JW#43We+!C+q9>T||ff4KKXEOmraVM>Se8iibh-vuDX zZM!k8nHZ>1$IkREAXm;9R(_o$HRedgnE(l+zJ>ZyE91Sln+R_k{(YqnKPBK`uRHFm zN85NeP+ z`;)5txa1eP&qjh1;}yg2ertgicNm|+Ky}FT0ztlYMu6;ncP{Er7%hRF_=~`bAI_?6 zNhy9J*WGxtJQ4)SnWZ$FJSm zNFHVDI_Ttbdjf@LP=e8M+gF~soFZu~QzWQ%Qy*86qKzO@nU9Wlx(fPAJwj-4V#b!!Hzo;VS0v_;Tnk&&8K%zh8 zBfhh=+ghV{hY@!9V1Y}BssvQalzt1MbZ3IQ+4m%}6}(G7SW>U3y?L{#ephP#pam%Y z%K9BOjr?@tqYz+0c>JjQwW)e2d8~m5ImIsw0F}GNjG;zu+`WYc4cP9^Jm?d2bAZOk zyeo{!ej`q)5oPkDLBn{$fXr=*6c!3bksKt>Pcm*uk;-VX+3bkKsGk1$K2g^9^fmCs zn8C;+?1$a(N042K9?a4%N<+tC9}>|g?A$R03|tgz5_B7-6kVw@=y|V=#VGU!F9d<4 zME*64sroOPOYW1@QCQGWv`f1_^=#dj9wZB6=I38k4c9kMv8!WYG5Y7~Q6EJHn`oH4 zwHE8pU4v}BtMTv$&xb?G?yXlWh}+V#OS1dEZe@-U{@9yyCV#l58&5+gc^B3cWQG{^Eq}aND?9AsRa#?-4dCzMLayl>}zr=tRjM(5t~T*UMkv zCy(u#gsTMdh9N7?`=+M2`=-7mN$!(lC@V}RQRP~R6>5Y!1(6@nUu6f0Eqm`GqoTL2 zCK$7op9EKVQ=#w3z5?sC#y+2-M8|ZSvLe9Y4NCRFTlBdQQ+MM`ioxoze zuw)`C&L^=r3VP#TAKtgL$#yKa^1Q~~yh6Q@>K1=8GB9)bVu21Zy%EzB#F&C{98zCb zcih_(F4*>d;|4NgfQ`bb4<-RbGozP~pg=nkeDKW7`|WN$&?(oe+m4pmL#Wfw@g8GfCZWVh{+aG5g@h5aLUVrd!r`iO|~ zS{I!;4a%^_x7C#kcVG0*>DG^~YBIi2+1We@@$2drm9h44Ul=%U_32OX*`5r*`F zLp@{Ii@SdY7O|Rb z^igeN<9y@hURzU$Ka_r>tiuO`L7R&G_MT4UMl0<2cW#B{AojeeM{TX$xYYbi*Kk13 z;I9v&bIS~R&)Nn{e1%4Ao)$BkB`ORJYX~%~^$O%Y7k&DcHNtkrAGEJxeGD5mtNK*i z;>TAOc3F$7U9+wZgHFKIWFL8X^&@A3UJ9G9L6>t!*Lsm>&j`1E&V(BzFgb}Vc)SiY zpv#@)HzP#6PNib3Ua#=?e&2<8?)|fxyG-K@1)*&Z2}t^CJ<$0V&*IS_Nuw%kPzL5| z9#mbH&QlEKqF+aEe{U}al#*Cxh&NOD!O~c#qPDKVVPHmYy?;l{xGpl89U0X`PQx(F zYg{*BhDci+wHQ1Y+ToplC@FNj*r22|+YC>C@}!mgb~ZV$xq2u*PtX$X$=>)U+X%~z z@2@cUnV?o_&09D;Ktqr#fZwiJ#oH&i9l)JMQmGMX@-Wlf($qJ$rghGQbNQW^i;}Ya z>EW=NAr*mAE{)TA)qCjWywNk*nh!eHV`MSP2Qf{0kz+|}w}?Pm`SK$W?wunLBzBJ^ zyxb82@pVh4deyNpe9&=CS9Xmr(1fDrydyf31Z3<_t6AAA?J#?mytE7(zsh%~pW1WQ zowGMb&m4^$B=gl;mtigjTQ$^O_(mAa5sh5W-1d_lWwNC!qVq5%IIPLd{Y+xRN)GYa zdod-rcw2E0C(=13rMLR%=^o`p@+PW} zb3oCeQ@Pl>N*^gW`m5{nyhuJ}G=~hkyw?FeE`W@_GU73-NgF;)xCSsLl>2B2G(|!O z%(O~v|8_fWaWe~wb?UDMJc z>~yhESTTn`n&8GXXWf*`l|0}T|w~1BxApYl0G0*os^vQRXZvcAGx3e;wAk7k3 zn5|*C$R{iK_eI{8KVKKuBRtLbJ25c4n$a0|wtbw-HeO)hHLs^N>Sb7(V)T;2u$i6^ z?nPC8`ume^{iH|WUu?kv^h$$WF4FKrJ~yf(sn)BXZ~1iTdORX@rCV1a)D|ziHQoGV zI?|x)`-7??n5n!+FyVU(^fjl>bfJIgPE%TuBJuknQP|`v`{1PCS)MLJxlvthJKsd; z`cl@6P1UVn2N7cf$w>CPMVXsV;#Ckaj!GZSWj0j%@jyEcJK)<+KgFZmnuq(@5*4=j zw~@QD1VB5&%5D4z?<>-E?uheWh=y?`+pxD+SzDv$bUzUJi+i2%j^*w{aU=|K$GfU$ zo7BsI$?$Kq#1g7ev}H zCcGO2)_)O0#SBwMk_p!fnL(2jHSL@Af2qg~0_4(p3mPK}yY3;u zKnLHn$9Ac|na|Bcm|$bc19ZbdDF#U5C=2yUqcMvpf{xy)w8y_XUAA(j(u>Z;^H-et z*UQhjvP`!mcjc@)*CTb4lZ)Q7#A~f(s2(f22AS-_#Bac6*Isj*9v8U%P^>`4=ZAGt z?6*KtNo(T8o@?IE*JyTZ3!T9KxgAN!ZR`c#~B@}2J5fUV5Gb4?ugU?C?#fgE{6h8$7$yhprym?OZ7VmXd=&X_??$y3C z=Mbo_xAn?b=_CUX<4{By*pD4B#(HP#)whH`z4Vfd>rhzK^SgluaW2$ z%lHwyV$Lg2N##GO77yn*7f^io_HK^H@k{!t=bc^_6ao|@@#T{icYSK+2eop0h4k0l zX9HYb-gTy_hRM_+m_Y*!C;*vC1)G23<-~+iVOTIfiGvrkW)u9bDxJGJ-CLhHkh4dw zjm>gnlif>nT=o0l=nqmcl*bweM(;mpI8Skx6G@5$UgL7+%fpl?`2-V;v|lZnS5vsE zEd{5(w%&CWsrwouCU@u}p>*RJ@RX4ldO$8}hM3TEvTpc=#=VA^|0b-}r2Jmm3){K0#mL4;`z8!@iAQ{*bPHYqXAa z3$wDvX4wRjk2#_A47_$VHd90ZO6{s{d%S7l&2t^?>224fDR|nn`v5Bf?tJnS%eB+WAc^%%{KOaW)8dccIQ5VMqQjo=qnE2Fivp2py+R{0)};<;QJDOjNbq^!jr2Dn9@q zl&0JR8~4*F+w)t^bfGnic2is^bXG1dv;Lz6S65eFV`m(Yl&aUkY!16cX&s=b4xtb8 zO-3Zn11;L{V%l&6lLO?E7me{?-n6`SLF(0OuDF@poK%St*Krf<$g-P*XWA_xqIrVi z=P%zU97ObTYr>k}-{KCZVZTzEHd|cXjn791_Ld~V-mpy}Z-|q%Kl_n1F?4c4Lw^i6 z-(HGyO&FAC%mys=Yf;&76XcmkJHsFA<>L{@*k+&Wh9 z_==Yf5>{3C7P|_=K!<{%W>_b)P5^3iYCISWF!`c%B|3`7VR~`WVyz?G3{8L8dUZh$ z$;nCPwEdE9-F|uFNU!fKco`*v;L)=FelT$7z!Bcv!E|FsNMK6LX7_=D5l#U8@-A02 zw2NoQRG@Lf7S^?=k>5u%>2jo2nQ(`<|w9OVh9~ime_2hFa(+Jl?8qT7nqFL9w57zudlsA6`lJK3VP_ zLGOZiSgWce6B!wqc6R(CpXzUJaeq>?y)oF*He953JXogPZP-?{#)T)O6*g z{2`8Y-y4&cznS6+SNldvJ5?SDy)gv|N2~3(PkH^yulcZF!(K(@KhhS)(YOV?0v${E zS=MtFw92gmLzi~;kO+X2&O#?1ODjK%DhbquuKH6ez#KNekOo|nH)Ag&W)t5f_E~`F zvAbvs&!P9XYpTQyr2*ds@1gs7YZ*@>zZ998CM&P9%+~+5+vc!Zkl&-q^j*r6OeFSN z``Xf@r_Dq^%*mFo5lZ=D!YfSA!SHhGafWK+~-kRfQ!#InR^dlm#bSDW(agg#($Ep}_l~P5m zLDxcv*xntwLLMzv*_(ZnOs|VGgQylwrbD~(eLjW}&E{C!S2XM;#tN2ODK$=FJp)6* z<2UcU4UyzF_%S|ne4#&CJyzn9X=}Xy-c02*nrfb@q-6QK@w`5r+a;q0`KP|A)gs5K zRXR6Yf}|GH{JcVeh={+2Y|GAjH$jyU7JZBvn2|JlQBu2nI#LH*#^npC^V_QTebD{? zNSo4t^h)S(ZKcox0OnOZBZLUB-cCU`DHu{HUgyKv zoZTvNQ68AQV!zXN(VF~nlUexI$&yl>tHj$WX+UUu!D2f0`J9fMe*3#PWYkU`!;|^f z?l)&xi(uv}&ockD&&BdD?v^xs(@`1`Je^`BA-{rgutM~V2IHm633TDsU`J#eC7n#i zfcwEtJRK1@FLc2>SIKM**T;$J$@>aBlcMv`06AsK4w$+3?r(h^RH}Bt(PwdkV5yhv6{94QBE(xK_aDEHGz6OvZV@~UfU^3^U1C+NKXcp z(Tzv!wj)ww1!H~A)hpc76u0t;d~2hlo^?bQZ}~}7WP1I3(1~Cavpw^L{Hxhs{UYNs zp66M59}#`9 zKa-nBM4l?5mY-)PB0x84XM@|ExXCS@ga=E4U@I!PcYzROp{s9>bKT7lt~bYAMTKCW=M>{! z2O=RVvRkYn=-qRG2-(UiQvvE|i zy8Rng9}Ga{ylw9B6x4%X8a2xU_+B-eR=6BR@%Kno?w|~EBG+84B@SUI z_|V^2jOsjYTjY9rP6{Vq(#L7pOl}URA5S$GU%%9KBLVDn3g5A=2g?oatAC`=PJ5!< z&O`FluEJ4QL}u7p$PS8jR$IJDZ*{J+vm&nK(EVbliY8SWKchtPjk4TLvc8X`{g_49 zQkUyq(z@xo!R#jQNT4R{Lk=pw{2*vegv&9;> zCk+mV$g89ols-DkaOEm)6iGbt1m;#2{5)kpT@ z=}MY|m#Rhq8ByF^+si;CX&#!S<%l5*mB@ zRpYdw(>ukMM91AdqLEi8t3SVjFw_!GiOB(Jd_h#Y_N zIP5>l@O+d>xw?*kwuIzg%vecb*){bgjHM*21+xoSCQs}<5@S8Jai!MTW)&gV;YYg) ziJ!zKeg7C`jL80d`7TgDBl-!c4nM{fy-Gp9z}`eg12qe>s#t%zZ0q;~Wxkv>3kjtT z-``TIVz12eF`e5JnE_o>^Zo+A!J-{%{sH~fe-U*C-F9nG4nh9rM^+7Kwr92x;05)J0IC%5c#IRQ-MmMgU<9<% z^ik?~KIq}$jC;oH1`8aY?h**4eKH-6W9~q=;P?qlW145CSMHrJJFNLZX87u_Ug$c* zB9sQ)ZQ;~*RjXX!S*oElJ-G!pG&VKuKQ%!mQ$s$q2p;7DRC@LFlRiHNi3%l^l8H}I zV|L)M{PN!CrRn9%y0PBOEL*BaZO-W!Gp>>UGGMz+uN-UCMDZg?roi6vqIs|IH!R%d(qB#mB{_919QV(nW^pYDgAbL- zPMaZJeM)Y2$u2KZ+bPt*l|G~wwCvcGHBhGe;L;AYmR-9hdpkSpt!Erc>b=8hTFa}C z)z!<{-=!xV{Gw#lMe?%?yT;|-von&jk?4IFr4VnA&CuIf8yg&cD5&U`stPHq6NcSOHCZ-=BoTHP; z%H!1e;2?YHP%a_Ym+aRyOrkNX<1Go0)Ew*I<$ck4W_K(zy~>jA0P!S~uYth=mN3Mt zmF)lq zVOe(ya!NB$3+llb^+3LZ<~`llaiIBKhWu;lT}r#ATyXV-A1|I(Ct6pnUde{yJFJW3 z8K2riYZp~V4k1M6&j6SXCzi|k4ixml$}G@?DMEp4Cj4sO8yIB?23=ITEa?3XE>*M# z2kK&}tpgpEM`qlFw+BXa(6Qud?^Y2Q%%T!>Jh^aeJkJ|IFnGH!BgC*s$4$t{TN2e) zq#G&h9Vfr*r4zRMrBmPH*c5=wpQ|0zhBJUNi7i$uT!JTfW|*+YV;q*N^1MvtGU;5G zJL5|Y);in6A0E+gRNK^N<-6+8Z671k&F4#p21m^nYlpOMmm~T~AWfP$m)9GM#-%TJ z|8Yo@U6rSGTbrJr8^C63Z?er@!NT{r0X!!n8oxjJjCCA4Z8FaEV7tCQZGz8fHFJ8i zw4rZMw<#J$)Z(%)Kk)W=7o=me(L02#L(t(4(k3&rwZDWAYq3&`1W>OtooXZJl$ms4yR-DxT}PG=#$0oO0)Q3b!^CuJUmvIYce^9DKlDkY&!L)mL@W& zH9tnB119PPgED~4iJ{q#mm8E?T+YM8L-+RsnM_*EGucKXP%tO3K0ga&y!o81WUR`a zdKqXNJnlnzJ>5|HdGhlLUTbaihF@T$@z|Ro+bsk2>g08HxHGvtjmL)LgI=C$(@rfQ{<1SL9^x$<|E zrVG{EZEn|ZY8KGXZykr08Z3rJheM;HI@(?dt5{hV6>1ku7juV}PuoYvhX{cWtYr%H z%B71{mh^yHtEGC`Q|)h~E?@GKHc#@pz>5vw-_#j4&6)%Q(k|Qa{t0Ev*}2!#$5^SH zrX1_>D%JLOstL(#CNk-Gb>kV5v)T`vXnZL^bLFxF_5?-^s*#JEWA4Gbhl`Ow$HR0<=~v_2tLnb zIhGVDbU^uNc^{>)L3TUzysVU}K~yz;as!#TaGL+teSPtpEm2ad-b(C0zn-V0Hn(nc z7>W(a^js}a$yCvCyRT3v0IV(HvKfy()$3$>S}3(fA;_@X(!MAifUgQ|)85D8858N>ahS{@2YrIQ$mCK~H6upUKz@Qj0PiM97=bTPuw|d&A&P?mDfdaf&vIN&ZH&SPAeU990v^B^$nka8$pzoXB zF8q94Bg>2XSvUITzR4uhdNw+`Hc2GGt)0^FEe~oYUs>g~>57 zrbJDz?T<@TwX?i@>^J+!tW_fk6_Dd!pV8P@a@*Nm){5pH@u6!_na!WH z?O=91xXE7+D_y3`C@JwhZv8xnF9|33GTb_=V31j^)z)89A;S_SRvimrGbbwile<=( zKwsX7N)mOg)q)#jG!+*UJzd(wkw0C;f4VFf7f14;4GgTBKrEG%rmfIup z?AojFk4~cMf1XzbptJ~jd^XPqsi^Cun1w>Gp3v=$Pj7Z6GJ|pmBJ)Og(*MvDQ4IOk z110}NMvc{GBlGlf-p5w$^g9NFHj-?;+czzFON>IF%;%1rEEkgpblk7&9vnB_9ZpS& zTrWbXGjSl(uJ)umqcG#KvNrdtn3#qYx0Wy5vvkT2XFXA)I>cUgG3Dtksvv6!(-3%= zk~%#WXD?;@?6x60#=fC$C@VSc61R}`9N~#Z5CM&6i)VLag{~%ph*Rd@60q!@w46+O zO)bt@F69ucw}aU3f)puVFNwZv>O*!2#c;QW+BsEl_PMB+V3oDs8*{~&tv+q!jmSlw z`FRt~!B@$iw$DL57|drR4Sr0Vo+`V_dj51V8Iwco-OZ!+s8J#FKLQa`Es?k zow0^hR`9`K)#lDO%*pNmKIIb4SspN(axO%6X?#hK`Vp<1DO=%TW3MzZhR*yuq}fRy z<-p#re%IsdB}$ps#|-pP?3T+8`%~Mzo0rQqAjjk7u`TW6r)0JcMjehF2{(8Q;MGJh z_aoX_Rv(D>k%xnBG1EJR-HOX(+8b^}Bm2#Wmqot77Rro06_oCxLB}0q%>sPXr&*wEnz-DrNEA5ws znaeON#tfi&{k3ug9(yg`n4aEE=ewT(^gbOvMJ9rsloh7hrc@tWndY9H9knZ{>W%Y;n3ypL@|qx?J*)l>b0%5qabaV3AI zoF+G|IC}4p5uMu##e#@>2J!0y&PpO$oh$*VCOc)ge&ZU`q|ob&m6ltF)77zEhy(8I z9A+gQ@OU|qbrOhbTKuKK;gl&f+sFzDV0U@(%4OT?8m0_!4HrL~7#hdZt1#tjHbJ@* z3Izr=NJ^i@p7}{k3?`kS;^U2oK{>C*MN*cWsAYD&EQ2ZhyJJYhj>yeE<$n-KQB&1Be%&hIsrSC!+ zV?DBa1w<9=moq23B+ua`Kg5 z!d(qCJOGS<1&bx8=ktRRW-z-8dXd?{c=~DMW+Y^S4dwInQyp2JoL4g_n1$Smvj#_9kxxJzr0KUi7_k0ujYgko{kDTR<`DSIr)u}x+a5;; zl#0~*o;)6|iV6!Mj=^F~fDcBclSk{)F%y@+P5fPIadA^qlgaG~l9Rv^WPxX~4w#;D zP#I(@O67HP|A30`2SWZpa>2r&{>8ns&FiBW)6%hZ;|{MC{!Ij5S|>~R^uA`Dv2?(N zt#Aa#nJbsuszgF>6yIy9=&c6wO|_b+8s#j4!jw!s7ng@gUvy_YopRDgM`Wq=YG$KX z5a09F^0aIPB#JOsYOR(~7Zh~5(9lrG)Dir7xVdo4xbO@1{Z2y(_DkE63-0^f z_tqw$>Y#;DBwo9#?_CsxXFnFzdv6J3aZSYRpt8+he(E{5fs%aWJEx zt*v83r9B_Z{ zoVf0tVF;C~RA_e@G~4wJGq*oUa8Kmg=BQ|U8ofZAJIHdHm3U}{3iI`-=``K+`2FF` zeh?7>hDCnBiENQ6HO9Ba>z{VU702}rA%k3+B2E^xNI8 z@rH(m^65p)x$7-4VY^J)7_b%Ur5vvErBgkyd?7y1Rqv2OuxgFlwTN`8w=-BRi{Pp&L~wVcuPXS zcb+&)?r<-$*n$0~v)v$KI-cBsj?kG~ox6PFd8PlN?9?t?dzccK|GLK6;rtfw>SXCu6{rvKs#NO@ zZD;9}eCIlOJWijdj;r`an$++(b8Zlp$WYh(s_lNiovKk+ zu34lHr6ttc>aiPi+J1;dd8r&rQ6$7OFk7ycWAz+p-F}`wYkhZ}sFM!FcR1d9cj5>+ zKlL)B12Oi?0aS2VUWgJ+9wG@@^I=Ad%2PGPcIVd;es_az*o4j6uk9wkD|N6Kx!jH# z9TmY|o2YX%n+EA2Uj>8OuOAMTP0nS*Ad$gc;X3o#iT0c0`P*%59U=HscFSzS{l%PJ z$<2Y=z3D^)T%j4ofwUuwOCuri3=ShYKdH|92wMD=dch5D>kcDFe3|r**K1vVfmrGi zH&M=KVFMR0SC_I&brOx6_1qZ*x3xX%s!!9|;yO~A^~R_e?3Po7dYe?hmeq@+OHhEQ zh}BB1>F^eOxB%&I-*WBhKDE-U*^(#JPF)kl!oR8P0XO0&~G_%%`uJT74| zf6{cmsZndy<~fq!4EAy#JX@De{q*)D?@WnK$L>JHqrt$96Cqcy)$J%Qo0G*-z2mNo zx6xuT9>$~()HC19nct1&Vz}o)k=^!4!O_a&EVfR#hyEMC!s1V_L2&7d&ZAPY-Y#2W zfCs1k@I1)`3hPB2MNw+~;sz`;3UsIg6jZE|RnJcB8)%+)+^e48=e8C{{M)C?>w|d^ zXykG4`L@O3)Ru)(SYy$ur3@V9`FMRacN{`JFlYYlb$EN^wDo@H7zSP@<*q4HGHTUj zGXiTY#rb%7dtrAVvErK-#APRLeH`D~pB}?JA^7zDLPf{%aADd5GU;~rxLS2bYrBlR z(XV1Pa=+T=E__V~MR>PE79JmOj-C&~LY}QU3>G%}Afdt2`GzQO1Zvsz*x&Ul6J3It z9uKq$M!TT&N61WaM7e@40VUq^xNbgFpAKgxP^nnia;6Z2OvFEk@9wN;Ad2`^uge!= z5EB{kA+4QTMNl1COzu2ywHs~pAgfB;_0|>gc?aQYY>(i{*R7$SkkuB5O+W#Bg7i<9 zn582k6A2DRl$DY|_EGtz7f0fXB_~7z+rfe!*!4){!omoA9tc25WYCrp`dJ`-I5!Iu zHd_QqTi|l!Nrzr@Wn!fb*=?+3(Qxv5fglFbX`Co z8f|6y*ynO{>1K=TzfX1(Y%7&0qi`%eonk+=-`ooGz0|tjo*0j%j%l%UK;kd7(|GJ= zio%Kh4>4Gb8sB*@f<(fjKNwv@)`OUIPO$oHK|t<@^MPPQ41In5z*T$DI3aht4vV+o z#lzj*9i;e$VwwDxJy`OC!^oR1oKBykNmg1`GO}(rN601VN3ftAi-jdH4)^t|4}=Ck z+#D;k8JB^*o-OaIw~LC33J0SBK$k)@9j}CPMk7`bn+TyCn_1iKvF+CC zcpgNAm5>yddri;5Q4hIQKP#VDw&Spz)D#!j`{=jrl4V1( zg0&MLB&7e_^Y(bD;Wh{k{Mznhd4FLG_PW(-ySvj*<`)hnLc`Gs{y`%5YRT9IUG57P z9{;VPlZ3xaHdwLqGyN-zf_D#|Z&c5;Yy^x?6yH5f z$!iteFK2Wbm`LwiTCvar-KqfIs)K-4Qe6V$%95v+Z(Qf|yg#D4u9#kbOTP{-=vJuG zP4>R9uE4=I!IPi(W;;CV15tv*-(o>qq>E+7oQJ^OWFE;ccdymR!y1nGEEBN=0$J)! zaX~)F_ML0rUtPXs{#x=`pM~qyfAn9+9>vM)@XqpCiGgxOirBea$V8I#9LNI!;L@&r z`j>B`=$8^oJOm+T}! zSWI&$c3+>42T*WFvm8swU8_{ly{z9*qmQwCXNm9Rx1vHaD9wZ)sx&y02yfQVTo7Ja zTn;OM?l*|PZM|17o0Ont(51-f>X6}n7?=5wcjbTn{WjQ_x?zHH$oqGhqMLU`eW~J6<~RD#Q1_m>y*G8{^8!!y(v37TFXW7Id{tKo+336eTYrl56bAg`?Z4FO zxwL#mD9E!jo;{F-6uA0(t)lmk5)X&~Q|<&&JtZde7s!7Bg1rB=RuQwFzP*l) zo`Hj@lb(Z-p^mwotDcCoZ@i~-8@@S_KSOG$105J`oR>4b!1 zJ|POH`S^1Gf{pgQvyH3!`s8@4?#;FV=6zADMy$N|S_+E>tyJ z=skgtFa8;(udmPN&Bog>t6&tVH2DEP-QhsCcdG0Q@@mu z^Q8V%K0fEL1){8ch7@czqfbMNuaRhuC~7aLo*^kD{)P4Z%adZm7TEPNpxthIsi^c8 zJqTLq;Fn4{pR?XOqb+CLOZ{+H$_}Vx_JImN>ukXjUqmm^rsdV|TQ%w5DVTN#vlNcf zit`SKn&w4g32gS`hM^f7Zjlkc60biy1F?bnAaeB$jE1`#Ab5FZ*QbzK89Vvk*d>=NG8e4Dl7Tfw^<48mbQ2QUih>+7?_l9ZQA88E}vH2F2)8 z2C5psa0qMfr8?Q}0GVqjrN!ThP@?yx6vhVO=%+uJb=wC%ATl{3;Ab={m&Xvj$ULdA z@f<=JID;@?|4#-aAq-R_|C50UmO|p}o$s{&WMKMV3?K#(D4As?{(}M3!PAdBeK?mA zUN9fcBXtnKLSf7B7*81kOM8`I-B~?znL(`zsv@)O;(V=biNi&UFKoM`_1OiDDLL3z z)kM4HyV;^gu0oPL8}Q)v-6fq3^A5|J^`#UZw~PVhiIN?JF2Yowiq|2uKNS2G=)Y4y z7%PMD2!WmjV#JC5BL$`gkb2-odUk)TiBWW$3=Au}zsc!c6FjXyabECuXjI{Ma>6rl zt_bgA#lE65h0138Log2xT3g>+t7#(dFJ*5yOg=9MH6f$24b99Jox>Iw0?Z<=2ts>iu?K9(K5Dp)m{m9n-!|oSrodEpLihQoa{_m6)1u6u*_ZN`s2CYB3v$Cm465c$ng{_&! z`Mr7hwBc!?KwO=2mciOY=;~x9tL%QkD|?SyNDu2>`V@Bw~NO7Uqb?}E9GI4LqNgafmWZZaQIOWC-#&sf@| zn|Iwy&}*4>+NE@l*7fes$Ub?_yt4#!OcA<9%m+M!+mShK3cW7kkSL351GEEPrfNQz z#efZO^o^?%xQ=eSu)C&d5O6)1|0hJ#>D-48-3ch#p2Fq!?!5zr**3gPtj)9@XxTpvg+1COtRPQ7Eh|yBP}m>+r1Bt|9GWlH?znF*{sHfS))sD zB9(L*Bu{P%bM8JjjNod}@!Em?>Z@9O$fFP>Mi-Y${QS&Rj`dB!D+yP*psbmx^#fk2 zuiu?jptIZsTSNOLH%P20<~$BFDldbAn{gsB@I6ysuE~q$FsD6`aiGBZ3GfH2zasK? ztOU?w_x^>|fA$pqd#wJg#Qy-+=>MBwQO$%Vhp1J?vl&NUqUDNA3H*Nw)?Xp{J6L%F z_&u@^QQ5#ksx$xRq3U2{`QLi1>GG_9Jl3>2Lj6!NA2EIO?Ck7d4cHi;4D1PhM3Jxj z7JVXdXQ&iHBZ=~7h+Y8uAi~VF8tA5J7ulK`?!)P(vltg2T?9`kWw~<9%~r{)5PN;8 zR&<4ppLb;HVljIBLXDlM`ftv~n7XeuIrM{|%5AL2sFGOnYt%ErNHwxGc)x}&RWDhs z>dc7A=S)g@g$C27yoHWo;%VJJct$NGHAQ>)a`)?iY|5FhV9l_$d2$6u8P-@c_g`93 z&M{cpziy@9L6YNPtMl(2H&Vmq!{OJX!E7#dDLmG8*pj9n$Kvt$=3ScdV+ME{va&aN z*O1c*!h3%hU^$Do6VB;mx5G1!=t(LUXvCP=oGH#9*AmK?Md%p zox?ja)&+F-kY*T$U4?>@)H)4#r=MN1H^_B8{06ztzqW=V8VX*f_HtrZ;G%Yudh4E< zvAeGBFeOYGrqHu{m7m*5lSjE)NecIcbba6&$hMc1ky+&(#_!5 zevAhmM{XZ^an}7$WF`C|OaBj9FI3MLx)?Dw?4 z#DAc>Che3QT?HxAz8wlM#mMX#}vqEY~e8XX8+JoDp%@0fh`C7&b^qb_&TpbEm*;o z&ATJ>FuSO!sKQX5Qy`nb>}6-w=G*`yYQryCkCAJ5sarT}w&=6iX@Ubbdx!JWEy6e( zI$u1`^|C<#wTVjDRT;73&Fs@yWku5MQzIvkEf~4v5@}h0;*Nv1K}88eEvStIp_-{B_o8ggjy{hLmw?4C%_UJhrd> zn{ZZ>swUOgaw~qa#(dn?7!TK8J1t5noJ(vsCY9M9dwTXN56j=lZ;usUK@71gyiaxS z>5CHP2}LswtlOipM!^nHF4!Px)0onld0IUO6MqKrKPg_!*hhWHNYi4RYVi8DpmNFC z)2_dI$+r_BaoOE25amb6FcFqs@dwMlBKCJI(IM+zCJ;$BLhSv2o@D%8mVcY(r7K9w z`tiR{LkRvp)f<(cx0pk1Fsy}UwlN9u(L;->5=2w8g(}Q1fYrfn>mA_O()C&7$XW_) zGeK*!wmm3NIZK8 z3$Joy5vk9-9mB%$hA47J&yPL7_ii56eALZP+7~vi*gi zUFo!?;{JiMz0CXW#WB+noY19`UJ?;%Z=~dMWJ=Vh{iQ?gGgyA@^7Wt2^(mH2j0Xf9wALN@3tXC}fT}-?OeX>zh%PBu~-5vE+|q*JE5S zS9ucp0)u1`&|x7IM(%UXW!#3mwUyvOXYNH&W?no9S=d&3b&0QWx}{D3Zw5Q zIw=YstO~s4HXG=LgE#!KDD}TM`^u<1uxv|QgS!U^5+D%V-91=v2=4Cg?(PuW0t9z= z55b+_?ymEZs_KU7>NjtOwZ27Qkw1IybMDc5o0Vx(!e$x^Qb)sQ*oovOO6ll_aCM|| z6FJWdB?~!t`Y1CMGj>%eP^#eEQl8K6dno2m?uX9$mcAv)o1%Va+rXp^F4_$J2QRXd zy7@L7fpo$3I4iy;lt{SiAv0u6HOf$Gt*GTm$7+rO&ax+W;#^j(g((J;`knzsbNsX0 z67QJzWQ=v%TQ-T!vBCp0Am&v-L?k5OiO(i9&l?Q8fReDihCRpJi8kH9 z#@v9beyU*YAjC~x#x2H=#t1+@C z5y4>2O->4%Q#Ad0R?tMN)ZG!_OIC+OZgJm4z=g6jM5ls0@t=rmC0uQM^ZcK@T^E1Z z4beqN2Aq77OtI=7lZTc3WJn=6(JWFHq%aWFnMULY14~doEk4SktCnWzADddx7bHGDe1D<63AmEgKfwI*WCa#O&XbjLQ&|>hz4N~x zBe^u6hr0D_&>D#JW1W4gSo)mWU>M3g-HYXxXhEhgWI;M%*gV;!5wH2-q>0IEi?!E= z&TDJjgQG0Lap|~8*?qjx;>7We%l&uO_mYs;RLP-VaeV?%l?bpYivQWB{(Rf**)cws zapGhff9Eh^cx%28BEiSxK)Hb1=|tj!iNMkLe()Hz@pN@Y>39`<^^x{GS~T=Ld%@%*4Jqt8x6Y~pp3{3lS1j|XLPhb~~mij5F!U7U_ z8VFLC$o@@IEtOk{0^^6b%f0Wf1RUV~Z;J|k3I>``Ab+Dfl1YkoNXm8gw~jSr&eWG* z2p*+@;Rx=7JrUzT8U@pZft$(;q7hPd01{hI0oU*=Yju0r!VlHY`&xLPS-+)0X;_q$ zmul2xI;!6XFUA~fV?Dyic7@?Et&qB&S_|=Q?@To{=EhWM>*M{mjdsTroc8&9%%vLP z%PIW%`Bml{R7>};%g?^=B^$4KiYy>@G6e9%^Iv(g0hHHt3^jGFEi82{ z9L)dK9Wje)mIC2L^&9o1$Id0N`r7 z=w6Nc@8Dp@09txr`&VRLA~c~ zn^*YKD%dq>Jg^?dQ@O&}V`9xUuaUmYmL%a$#7*xsa;qNA4C>y0mkYv8e>IpmVcH5+ z`({6MM=8cp=;z=FChI6`>#9MH4_2Y2kbaLK;g;Qwhiy_MKjyL?J1zaD1M>3ByX)(W zdyr@TUb6I>zc>dTU;RJ%qx?rZ`#XRC@`V2;kc#{9sn@$h09MDVCs;{KM^CGe1O^1y z_j}6BDLGU8;{-aFm-Gs;(hbDz@JF1fFnU&(BTk#mg~moNu_DN589_JV4<*qq*BNve%uwTL zerSp4OG8cwGTH`oCeE>mLP}xTTnPm12ZrOhLXs0J(BBrN7qm(-xZ}lOTb?K`Z zO`6mj2Kw%V7AvPtb%HC-66cZUea^G^_P3DgslXp;2k z$LW97(k;*EUa$X2-%FBS)3*UdVaf!cPwBs#pQVwxxt_HqpwaUx`1gw%73<`|?Aj7n z!A9_&DnjduAw&4!hUjM2r_V};N@0O0En37awzuO&9LF_ci`OG^jJ-PO;>RRC z{mT?H6bf0ISc$zkdLyav>Z5(;HYOG@+CRHIPPy27xNmG>v@bCl^c;e4PFjSWQVSk~ zkRE|ZK1ki$mBkj61q98v1)U`YmD=cu^H=C>?iUTlL=!}}5GNI_ZLrrtYhbwL;9S=> z-&vHN&Koq(mfSJCtCNNENFCj3{Vrm5EvZkVe+l0TGRs#=<8AR7uG9y}ZG5b9^2_q- zd&PKG&lD+A3Oe4XLJT#>VcE(;{a%>#j#Yf|rEeA4jM>DNY;>3GQmNq^!Qu3dxmm=v zY#qVjUwSO|SeuK{n%ONIv!+uu9G0T!N4XVuO_rGHrD>dhdGF;Y(HP(7t;%TfBbK#9LlSf_|IpO_S!(hXhqQ8N$i32xPmm3U zWW2~;B6&>rfbEX)JM<;*oAh?bYcS0(p9_W9Al=fu6CeD{XVq7QnvP`fdy71@1DAzG zLr^>xDM@yBwDy@SS6%h9_S9y7cUzDIi}wvBcc4(h= z`bXbp3$O|!b6q1Ht>>D}pCg{Sbb^Zucja>m+}v*6rv|OLaLK>iwAW2Io$JXC;fW4MsoPWT>`4 zXV({|0CG3ZIeV#)jZa`(PUqYbf`EVF2aZnH{%(ZnzJ@IS1!wXe{71bvt&L_a`9n*x zpp(!OEUlkgB5V|@1EBAS?Frh}P^=%IP0Ez8vSNykKJL+PjUiaJUsvZd*HWW;_3zWe zDh&x6KR7Ogzy+K@6OB&5UXT+-GH#T~5#XZh_)&~4Gu}H+uvi?A5tjyGGKXQa7nVmS ziy_A>_+P&3q||fVNFuY7&rLnfyPBX1BT-(hgBpA<=8&8l)%o)tG-TiYLO@CA%vg9=7? z{?;P-tE1Q2ytaj%<4X_(B9ogXf~X)M+0XuU9ZC%BSJncdm}8g-DhC*XFl6Oan)Z;& zTD3t>V~q_AHT}ntYlzF)9u}1hSjCR8V?tLL%?@BjI25fOJOugJroa>{n(7}-@wXHb zPRM(Bq#Tef+DK{`Lv}4%-HgOxDvX<_)EnQhNFOsN#O6fqgM~M$o9t$uO2q5Dmb=*# zc0Y;w;q6EkARK-E0c$}wpNKWJCV$s*oc&`u5;p0Yx65VU*zMbxpNn}M0`aKEUcZX; zlKwP|GAFx%>Ik~7g_BD}c24{iW+NCLm*5bFT)UyPCDj!^jF@cJd} z-7F?y)9F}8b0hET`r5Y7K=&(yWU9E(sQpZS$z3D2_<>RwlXj%i!iwbq(4~)2G1L%u zLo;_m{R7=~>beo-UDx4YN`LG)W2z0e=t}L#Ye-pfBmNUg{MhN!&stBd)W0CyF^)JC z0%R%nMauZy9BaL$9Ajn!lCX5_f<|iR`kR$ z&sOt&9vzwWuXL%XZK@Y$F5KW0%G|U^2yyPZ(3fdGR~x*Fc2Mr9eLDW_d0v9}8eUOn zR?5HNW&3B(^H1WnejaRjeN4Z`_?S%QEkzNkr~sOb+$lUcG$bz%^??D2+t^A78oT$kuWdF(CU0BUH@#H z=|plNn0Webid{kptYww3?)F*1{UrRq70flLOfPZ|S{PTAc})^AK!60|kM zA-#~F1g$2AIg_hNnU|)ie}8f4J3iUm5iB>18(e*45O;)Qgjq=hLxbgL^(pWAtP!X3 zUjO{Q3SqIqmTBiK=d8)n(%MG=#yy#vPx$B;fqQY!821v89aZ=qJ^sRYmhej?Ut?TT zb3FGK#_a!J82=X`13>;NUr3Jp7sx^IQI;}?h$KxA$lwU=on!6a?D8=yryLIejsJsG z@4+{rHZ5LmHMHSVZokCpkhpxMe~Ghv&C?Tg@-tCO zzPHEv;LXRRl@9cs&Z$Not7m9F|*$j%j0F|~gRIleM_pV8vT zDs|!%f9=zm$8RB{{{}gO^aaQ-p?nQ8EB^;r9)Jf%g#-e^`a8(a^DBU|meccr*)7j$ zfx?UEws(d>8X3tV;~UKbRgTCf%I~!xl*JRv@Z$>^7cwQLs)LYiAV`uwc0V{doVR~O z^m1DUj73jl{p4mT58tZPsLdJ2nZCWbEz+*x6p#<28VxXIUupSO6Ym1yTo>pn^vO_9 z6X_BPSr^SJvsEY1hb+kjGJK>v0lp>@F2saLx>oTn$6zGnxmbr#d^8G{HpI~&fo8?+ z7=pDxjX1Rg4FVc0nn$j+o~8iIA2jqd`W`yN5||Es94AC!Snrp+VNa2vr3mw;JJS^_ zweG~P_s$rH_fMP(IDu;w+$0v6?49!W9|D6xh4N;gR~^oEL3`|ytR&dkZw^`24Grj! zc20R*q|aU5(&l(ZqblObyQgBL3~m%Sy|(f8S{X}Hzl#km%O^!i$pT8ykw(LHT4RHp*3 zIQ(k>c*_~ugw37P(ZK1xsg@guweeT$+DB3g1h%T_rbIm)6eoH^FqgLr;1MYjqyv-m z;lduZTek=oi!G*)oo=&KGYKWFvkBHrXC>ZlvyTXO73$w<0RJ=sclmX#+J4mo)^x}9 z@OxVDrPyA}a83U`rof*v1U#ejdY0;0h8BPxn}Oax3o#N=o6tAfAEZ7rP{8YJwiiU| zwaB+Gri*x4Jbb7k3=9mmUm2j1fk;}tmiY;mLLF?1ht<7&yVBCPHk~$y_ZPN_7{<(j zAjFkQfMEN|hFmlVOHtHU;ZGtRwRJR*jsp2t$xcG*Og-VpNX${Lg7An4mkVlyiCRI`c6Kv$VN|VY^=;)^{xQUrAv}j-DLF~MYhT{Yu6J}Nk4s0_ zt&iARNQOgK+8YWw*WX_&wZq3A6C{$*IOmeJg|j{3?;IXmE%3f3-IlGtY!6!Ci08@7 zaKl$Y`!R1I)GnG%Jjs7zo;|5_NVfvKOcI6Ju(d65v?md=OK}y_O2Cz@1u3A5Y?T<8 z-bZkA2&uPeFIi*s^)!BfncMjmeXx=9Ji_-h;(uZt|#Wv#uu7 zV`qzL?7n!ut|nW%2Fs)IaWgIOQH!+4@6zN;$-NfiLl^z=a}~J>kaPdXWTlRUnHiwb zYhz?!Ze*_cEKMUFz|VlUzfGRi=_mV~S74^n%+JVEO|7>3IG(O&0!tI&y8&`EU~@~(-F~T94)u@ZFK(|PMYQHl%FAm(w0(>ixwQr80J?s(}$*Q{;||Q zzGgJuxMCn{h229$86W}1D-k2Z$3a(9ih1D=Ja$vWYK!~t6f`y}l0YkDk_!631WBpt zjvL}jNa-ch5f@Ul2{M@n?Qx?pDA+=GKceAz{TxU=Y*uJ43D$6_=}xXpO0HZi4A1po zn`6YY+p3en8$`onUzZXLD1hfYk{MP#NvFIhy;2VZWPW466Y-Zsyr!sOe<1EJivFW5 z`d=veS2W-!%MK_Yqo!_!1^EEB9>Bq$hhRu3e92jW1kKyXXkkEB$(gc%!3n9od=2Zt zATw7G7l8CJQaH>)o2GPAlTK392Y+)k)8z%=XgafDnaKWc9L0)QhQ8#ewhOEDFOI;k zZ~+|M{K=6Tiyq`}j)?!@DETEvq5zJXKK>I&KL5zk{BMrzo;f1^8%H((j)o-4BYvdl zu}k%dqu~kJB?gD{80kq}Efp?(7A)hOw;rCA7@pNH(%Hxex0e)NWIa^qH5Tl}ua_Gm zEaD$^kw2Si+7fHtbHiBO*>E`j-Hdt3#A}YM96-Iq{`Y3|oR9p!nbAoB88|No?CNB~ zG4Jp4)kta3!;Dac7TeCyddecA57ZF^;x`>>Pjr0~%|#2ud4UW}l-lPOj4P6vZl9IJ zJC-gmIqM$E_DJ)t<@bvwt6&)N4`j$vADVxqx&)(wsyz&w{KRTZdOwm{;fGYon&N(;O9pPq0uCb`o+LB>M%bjX~Z0$b}cZ{oo8gCKaOv@qwU{$ z%u6O-b0qtX)mBh z`djb9wl+HsmM-Vg;ASF!f@7cCFlQX`5q*nVetSwqRJM)*^3%$h$JK_hFY`g#O>W1Y z(W!NySdGbshlv6OE$M5YFQBkBT`{Sf*N@_jBezd{u0I=2e99*nAcL2eMf^!6X}sB? zs8(UjWVA-fhDpw*26D3eTw1s>FZ&Spsz|3kODABVa2s(lbBnXciE_y%cj=-9_T>DO z{q}co^pc9#BtiIOAlw3iqUQkV?cakV9XlIa3o}g}Lp>c6Z41ZeGbk>SRvIuX@>CKY`>}Q#xw3`vx)#Xj_E21*SA%%1CTU@0Rd+kwk+H6Xy zwwD(hp{mEmE%SOsV*C=ln1cOT0JqX z)xX;56|GrHJ}}3sDAb*i8+4POMC6#~#I4pAsfZ~LC_Wa3cxaN?9cZrP?02P!IJ9sz zsqiY^EDpgZYN`9PUHMx03Gq|wuF?> zF$%v=V$n!w6X>q=J4EinWRcKgOnL1uYv8w*rk18^-_>x_7Oqp*Y|O~=S2#e|e5Jp3 zJ~IsZi?0rK$=5-P7?nzic0)ALN}8lpoWIzqc$QIoCoWOw$nWUm##mWV{lyR#^J$H> z6!`_iP`5ls-|R=Rd*Z_CD%tyJ_Q{NUYch;h?&;|RlT!F<`I(rdTUW<&@ATcdA+C>| z&bWSO?nc|jeSQ-6MqQ2NM_WG2?AGa&lbwAwh#bntbyTpH=P=d(^_G8zr$g9tG;${iL*e@xrF1nRY|kR=Cb8362LA22WV*Qkc6mXn2@?FUmW zYXiLx_6+~t?gGSZW)`}7fDHi)8$C@Uz~Jn&`GiGtTa5Ey_AJ|^lI9tSba)74%0hmM zGWAVtc#AC$jml$8Ikju7iBcSHHj6R$HU|U+l+qR4{u<P*=)1iF*vkW&j zg=XsR^romhZv&1?aD`$qB?N+^taCNgYNzBFvtlF#3J&-RFpcecJf-R+u60V1}j^ zy5HOS*&gv70;Stk!KoTcDVI3*qItsqaobjuK!~C(> z`%R2l<|pLB1jaF%E68#?!ZB^cNFhp$s*{E!?eLz0 z<)0UY1AV7~2b2h-AGuVIEjt{^Q|1)D4ZQnYX~fWo`7|IxNg$g-KlZJ-Zx(aosZr|S zeG)wvw?aVC5&a_u%&n+ghFpO~O{5OELw=P?CRg#LCKo*CXt{mP_B8%M8kbJ)BsmA!USjdgGTBp;}nf#^LwV;h~<^vv%@dd`dY`P8IdatfZz!Xpk-Qs!+2gU`cudD zvgL*XdL z0Y#LloZNj++=#rFy9Ace&U~!rirEa!hQnNCyV9%MdSg!)Gh_Kn38<6M9caHD40NPC z2%eTGJWyxVmxUNr2E}AG>^l`w=T&ZB!uwWKR^iqRq2g7U#c86?&=8j7JZ5*8g*hU3%1snxba(^Rj`4i8OlBIlKyDli+PuIFX@W-g@0e}!&~?F z=MLMuoT47fKkXccSq*pRaw~OqsXy8dshcvOf6C8Wj+ZtlnZ+4y09SQ*@(?c$o4fi+ z@5* zNh;KOR9Y?{GShaY7hRxMY!DRz_(##JkVfyyC zfu-KD;J7v<$$a)}#8g|j%>L$gnEDdn*U(Q5UBqhvEa4n*6#upL@TWC6zIN+2I@Wr6 z=D&A$0p4BvkHxRtm_~CHUR3{4)28}s5G%`f@5m8hP=QO3qC|9qp&~OyLC8VgVKbb- zUy@&jC#B8QiET$Z0>e$$a^dP-;A${3XT!EkUV z5GpmEF3ccp|1pbNZw-?Lw$ziY4iev+blV4Gg~SnV$tPk3_8JEL(;kH*$daeS*H52R zg8M9q6$Ca;b&OVrc})ejyh8aVBQm=eYZ&$@`U|ciapcNpHbJX(@GtZXRpcpVTR#w{ zeBe(f;~&^^p^H~Vwt-X@@`&{k5(~-u%r4_7ex?x}Girb>DS1LZ0b_@bq1t0>GHJYE z7z7^ydPihfAQk6OTddMG$$*uuq!tsk;%qh(>B`OIQ}ZYH}RULA?8Dq{^O z7FH(l68!hrypQeGT0M597UcUd6h=kzpX+HG2F4XrI)lZ97IkUS8Vp4(o3;%2L*6j5o3om8gOyqnWh! z7~?RYRwn3gkYeQuS0$*|x?1?2pE0b1Bfr2YF-lOQaVj|iVz}g_-DosQFEx4!%xUpt zFbeGg539pDZo{&*ZPS|O^AwQ4J~fy#K3!>GgX%%{t+nl>mSvN8k|s1wdi4%%RZzH0 zX*p)(!OCr!a{>Q$hcl(0!2$~(#f)P7qn<_eM-~2}xCFe>gx;py+n+OO20G5SVSkL^ zywvDx^;Y^5C_4hw``o5xe(gB^Z|c>2UJU~%{W&hljgdB)c#ca%8y27T%oi0x&`!QY z&5=&xQ-!>xpoE&g&Cm75NR#Xt{$X07pVvqYb@6qjzwFl-!rN=KbI|SKMvUg5TT=F& z9;NS-UIa8wbZ1S{r1Wg-U#ze_+i*E1fx^A8!FW1!C!%cnkgc(dh*bmqEOjBB!khS( zh>jw!`mD}b!xn_`iOZr!`y6sUyL9EwU_$phU)2F_7xGHpZd5D1iN4b?Y2$d$GhPRm z8!ayU81DLUy~g&d+UE%PHFaS=rg^w+&p{+q7*J}*fW}`wr6FzJt{O@cdMVjlDc81% zdk9u|7yE6!5U{Y}u@8AhFoRm06mKp%zTc;d-p%W``C>`;$P_N%t4g zY^-TR%f+jAfcKPkFDT^)+Hy{c!}_fBHX_4SQ{gga?*nl6gF?}nvHRbdv<&yioZh5x z&gqS%8oYxXtjo^ujHJOPB>3(w*g|L#8PP{YxQ==X0xau?@{y~U+Y0qNIuhK4Js*NF zD_f)8j|o=lBJ7qy;33~?7Oq1VZ1S=IB?A-6uYix%m*Jd#*P2nF!OJx{5u z31hTVpLP@^ii3)8_LBAFW7?-y4=L{Vfg9xxVn}J^>w$Vr$2U`AI~!ya6HlJUDZl=g$t=|c|DECy#Vj^UfY z6|r>6w75OXR^GURPJguk)n-y}Z>GKun)E;L#I{u!JJZwgfF|h4{(3yVgF%JIepDM=93-J$2YCFXf79~S4s$+w*x8Tp>dMTmT;*x+n)V>CYDiRQK5&h5N z0!;cmJ4y9OX>q`gcelZlU3Uy*CO$_{K7MreC$LO>m{mcQCh5vdoMciGXmn|J@FRE0 zqg(q%!5vs`QYZSMkMFlbx#+V(OLtPB%6N|tcciyg;3eAMaCl)HgYPD*qcj;A(izFk zN#=$YO{#`#i$HDEMmykO*~a#27Zk;AU?S-_*Cr2~4sUY~ZxvvCi#{>$CahsoDr4%X z%kj~nyv$SHdxuWpXcDGM<8-mDuDxdKC>WrMsh)Fk?Ij0u`op9LI7pDYX!*pu6cOea z6wX8r{^=%Txv=8_ne52qbm{0cyE6kVJF{m0acyOTIo1ueGxRn`(SDV{;OX}e=u5O- z<7mVKrukl9$wG<2UJ>?5pdI#9>LX-057wTla;3){42mi0SIYotAY#<9#@>w5K2YUo zG$*pP@@poDX>G0}Yc8rVQAvZVXj{>3()}=8d(t^wscw1oeAoRC=&Cyk8Sl0X-BlHlmD{iH>CtwvYZqjrXo^yO zU~eOy?s*gLmyZjr&sX4Xk|k#7d~OQ{n#Pnf*v_O~{Ax!nB{9t=sJws^dbWA+z-=>HQj2GzgO6B$QWnfd{cRjXwM$w9n=lSajNtnfqbHhS z$}Zl^fVpkUJK&Hr*BOtO)F1UG0-tUjrrSRhyn3GK%?3lvC>UITvuf8kPftpJtlCwg zEtw2O(5Kj5_vEij0|NquJCdV=Jt#;grV2FQ!ejc@#y`-YB`LN@+|-{HaV(NoWZgP< zfm&$>t6Qf^p2(xgWhD${GIkMk%>d6pF1IOu1k!Ay)7d9pbvTAPLjc^xK=zg?hkm9N z$X(~n`GfM0Wh`f|(;H-Wn;uT)iw6EGCF9SzaN;F0MpJ0oG}gnVRip!GM^WWh7_0YV zTXqtZ%^z@<&MXnP6=>d)mx4WNaBPS&zb;bcDJy zJ^q^AC(9nc*g>lb5t3A#HpOOa?BQ||$}r#KN~l&oLXU#vZ zy(Bm+H&{3MRNObs%ph*!!9HI-hb8vle9$8PAS7wP*nCg$_`A&eQe3ZP*GTn%1p=rt z@&HCL{s$xdeQUsTZmIc)CZCP8Bvw)yg%`8eKvhh2j!$(dw8?24(Tr2%o%N6SE)j2h zPfI!aMZCEvx4}bHD*P2#M}}W3UX73lr0!7C_@P;}x4=z~KLYW8JXKZh)D(8K6SnS; zSZHMAk0O&mTN6tK3X%59_(s|YFos3u=PdfSy{UU+?uBNFkhp?00~*l|>-CTl%pQjpEN?hC|c04QKREn$Q%eq3>UPnho4{I%s8?vp^p~T%qLYf zse98Xx5m4Ov6pI=kk(*!&C<+wF;n2wWufv69|L&E>;+#T>kgAf0$8PPtgh=l z8(Ift%~Zl(U2OB*0&|>7g<)JZYElOGFI0KqxS$RqyZW!B%Ta_i@!?_B;RRL9n$-pG zO&p}f5wV7tvy7J8VUN)`APL%3Eul03$tKi22zQ(G$6TX121lPO$}a>9f=^iKM{O=V zRaC4#^wulPb1dl<1YX>4oMuUnxx8C-&x*yFwk`@!!16Y|t2xy?=DVv};zO=1%WDP) z^KHlQ!>iOUl~_v#`|Z)qk=q2Pf@&z&qL*(3$V=a&DGD9j)nX!><;RIQD>j(+ftz&F zf>C2Ns0!4NcfD0_5Kf11u9HAW*!=~;Zy+$K?%!aIt6*o;eW4*bvjPrF{>|- zcJc1a9my$yn!q|C76*E9qpF_fiTJ8{*YrHLn%SO@^D$!Cx{h*`H*BN;JB?q%dqMMH zz-ncyu|>3G5OVqWcQx&$0lhY@0-GO_xPY^7AMhdl?{UO$)B3kn=|#2!dijX{2D0Nq zh9MS~gVYIV%b$>k3o*KdH=ODrWOgc{y*HS`vl9rFRJykqc3{>@V-OKF*>G zo(~8}ke%}i+^xeNh9!S(xH)QKyPC2#w2f;!DeEITn;Pu z!^K@oW4u_BYp|iQp56jP+ECnw&@7gbR8^_y90~g7$lPNukq|+mgvzd6x>@+_9vv{g zyb;u!v?{&4gC-G!j&-SdwGlzRa}_Gv7UV5%{scpdmF*znd)6@=+EyPV`rZ$l80TG} zY(h+6ngxgkIAF)49EdXw)M|r9fyAd-A{ciM@@6 zf`&vn>aw-Kue(0l@9!#p-xz16RFlIV?DF&KB+l_oQxQR%hxU_9*Ayd4WrR3C#8B}~wF-DbQeHn8xNNtnDVIX2NcEs8 zM*^wAfpwgy1noGLMNzQo#vv7*#l7Kquzx3I_kLEx!xHIjW)$V8ga8PLE=yOVDp$Z_B@yp4~(iEFU*lZJFtO^0>;lIyhqY#+YJw7j%`E zp=W!X$8zjI|M)w&dkN`lu+h+ZWtRXzdjigmzc%UqAzb-~P6uEo0g#9x_86E+XrBhW zTLlW_8x^de3~!b<&K3LG28=jeQC)jU5pH&1UO+@xz1rm^yz+sC&}tvlaryr$NbK41%O^hY|jSWjWRl$%yN~cHqpo7vB>6^MAFX!G6 zv-=n{D^|0am7L5NKb?&kx)-w|{HUzmePS+afSq1CS%f19bGKLvpY>mA>i_K$UuxsE zYTBZ%6SM(AZX}>6_1}VAdm~#XKxf$k&>j1CLa-6b8S)%!WJnH?q%d1syv;Id+Kmkx z_9F96WG9AHbPD(yCSku-;gYcLn-nBmgknl{fpZN^1;*`Jo#uD_Sye@;;LF-ghAv+` zNfyxz%dyVo%_u$nQ%m%!s~^5Zi)v(wV2MD8n_n$^(d*&BP0V!GyTd3P~R80bm zTs|}_SdIu>UWzMlj*uEYwJV`(EOtCnVN%+ML@YwZU(3AToI^q{R^5!LDq}Zeomoq0 zOod|vZf+f@B^!^B#zhpZ88D9-FONlBiWuche*FMsn8d^?+|w)9m5`%Qr?QDV#XJ{OSYv70yrFN{%I32ZwjA+eg!GgLBxxhwVh#t?w_#ZELd)% zSs6=N>Y{ne83Gvvj*!mbIPHURkzvc{uk;D`+AjL(j4S4IA+HZMQg-%vFcKb7^D(YW z`3j%gcNi&e$&X;Qo(T9p1}or>piABkfMr*ZeFkPFaGbBQQTWPJiAR2Nb`FZp#sX>K z?s(8U5vbMkNLL(K*Zk!rE8mt&^?QVLh%mJQH zmG66Wut-j2jAu5DOfWb#KQ)hl(!kR$&&`PxZl|ujI~0*{tSE)sGiR}KtXk_Lva&Xy z8Wf{Hb44daJHv-K8*Iaiyvw$fbm25tpgg)nJ<3YdA zRzZ3y)jy2M6S}EC{794`UaWi!b*;5)NycJN8MQ>1ivp*Y55vM1OikNjHUT`Hq(3E` z{KQ)274`IWq}6oY0^N$T8Qh>McXXS^ZDNLJc^ITb&-l7<*M;-*?uP>>f;%hzqrLPL zp;5Cn*U{ax1I#m;hc(lL3sd#Z26gceF zw6vt8T%O8WoKU!kN)yHBoD!}OD4Jb!OC67={FZO1dBCiX-)MMhy+dM^>PZkJE<1`5>0!X$p+oQIh-bjxbJjR% z6reU@Y5LHSx5=EugRd`|SW~|xC>aziZq-j2HAop0OBJ#uqwpnrhatX#1IC*zwA*`{ zzWF0;h+x|wLxBLE?J(3lSD0X8Ix0euv$j3^C_8Np$npvtU`6{FJg|N}+W^EJDgHJ% z8RgNgvv|hnsE=5DIcb;vg6%Y@7_S76ooq{{zNC77Zwc>yt%f<(y-0JC^-7pMdrN{d zV40m}@5a1^`x*V07{5k;KREpIdCU1b0DZE52=M=g{`1K0bKYzg)e4xSK@1rEkSqH1 z-i-b&FpgY+zn>pcxx6;dCtB}sUGI=2QDhSUhZqNtMY}H;LI>sB^0&0!q)Z`v&yqMfxy%7H23}Qr>t3Tgz}R%X<0tfKJf+jkBh`F2d4zLq}Pm#`wufPNZWE zIg(_1OeKzn@7iOPdEHRz7T^nLWG$FK;KmJc4wEqN05^pqxq4ZA1mXS?Lwo5TmB?#S zQ0C1o0IWm1gL8iuDxJk~*eVKsK_IIBd4n+)dq8GaDMV~KXk1QFyk~XYC4b~vfx5D* zB!@a+D{NFrebu_soMARaQxgGDuq@b9COp!q7ASK_xKVg-5ffRT(e>z> z)@c4|<6904jUH0ot_rQ6(EtNE-J>C0Q0zbiXW4nSCE;Mprg0G$6me45cI8=q0L^I7{75!)f*|-G-|r-j3|H zgfAIzSy%Dzb+PXE&K*>lx8Bs;Ma(Z+I+tV=S&c;4_r&jQv-YTNp{cec9sM4oeu?mF z?8ihKQEdPwQvf(i|0#8_w6L_Z{NtX=zg3*#HCq#~*)sou-eLyz? z)vlx0<*u3eZ0Sm0mNZ5~3I)s7e+XG7Iu``WO~2k@tYQ* zsUy>ov_50m6W27w?QHjgGksFS!~xd2J4#Ut&Gt0P^O^#eVpQi8nr*e8Y{h=ba%`hR ztZNX;Mj9nwLw28XOn$mX*eau3ekQfF(NR-w4LZ|NiNRV)?o0m&dX|VqwTFdzQEJre zF>ZgIF^5h%RAn7n6QYAn=Weurpm!fv{^Uj5V{ml*`^MFmf_*JzaW&4F1b~!h0Qn5b zKb!#nI2cj_xF8LX%eWh4eu&LNRrNE>g5*Y?Fe4)ULIWmw0dkGTc%topI3s1~(7(@P z#No+|^5h9Aoi5sR3wjTX%h;|7csaybA!BhQZ%quOV4NfAkp8G?l>UgFo`?UOP`qm! z)r?($tnZCb74L%;Dhr$%#HJTyo6c8YThD|x$`!cpaIRqXUZZV_ZGtV>$8Q`V_kmD; zP@<|d;e6X6!`s;*4GT{m&5I1n%ZrNQ5&dOSs<$FnehoN6+?gk`9zB=fvLJ)Q3tw_NhJjXi?UcGq`{24tK*Ej(^K~;Y!{! zR8CH^M6ozdOvxgc2|>MbWy;6iudGx)7K&2zqo9FmWXp;%VSJth>BM6E*IDJR#wL6$ zjZF$um`Rvj%F^@dPh1xDl3;5?*)xj%8IRTLa6Y`I5RINka}5puUb zRo`N8b@_)gCk)oabhn{!QdZA#iMrvwGjz(6&?2e;yUklQ(+Xx}P2w_|*hud|$H^)# zIAYe`XFtZj26MH-oNsS}Rr4J4VrYw~Mgi>7jKp#^U`%a!S1aER;!flg2FmsGotQ$y!h~w{>ysLe<=Os5J`#rAAY;is6jG$B9FA1xA^U91in420+j+% z966tA@dxJ#BYO#dbNkMb8B7j&1U>}k%hlGmF!=XmsP~}fq>ks>WxFW{R7vKbHLJc6 z2{)U~S8nX|jaZo8k~p4iNY{qI^1KKj$EeP0K&zPA5LTeH|A)P=?23cUw!}3+aCb@Y z5D0F;o#5^+g}b|JaCdiy;O_2DaCg_KzKOfZp$l&f`!p*r-9z2;L4e>Uf)r06Yh&8tUS#deN}4%Kd1jhoD?Hy% z_JBA+w~3m}Y<0^U(*eRJ`^2{Cy%+&hojryKXnZeMp}ZZ#jWeloHZonAAE5F?NMOF{ zn2)=C3{q>SEm{9FNijd&hr<~o>Q&~WBozaX1@CBNF3BN43X~>V_RNgD+|X_6QHV=S zU7^*rj~tR39iXBK8P(!@n4Z(Ui-4Lr_bGH8PCi?0Ie~VZQ1&1RPiX}kXA})w;TZ&{ zcGlSeR9EMy$)^Jv62R@Cq5tvYJ42(lDd~BwV8-&PeN`-xkWrG43G{N5qzM$_!`A&t zN$w6U!z$3byRV(lt~6VlV!d|N?_JE7#poPs1aWD`iWH|UW+fNKjV_`0C$l zA@k7iaqGE#g>eqOfX@zj`+z)-d}fWPk48~xfp>u`4628$LrjmLiEzUmd%=>q9?2?Q zfdm>>q&#Dmj4R1H6*!Dlm-&TIo73Dl!gMq&i*2HWv>~gqN@+CAV{TC1Gp}UrXATrk zzCHBTm~Yjoc7>M7kH~~xE|-VACUeuXnUBPd@4Zv)Q3ix;5I?-L+`-@bR5{#V=6=6l zkaRqK5SxEl9efeisZ^U_UK+o;V<75Ug`gpRw(9X5Zsr;Bb6oU6#EHc|BKXY2m#4P- zZtVrF!JRDCp5WypozXV(Dt*Qe+~D>aO2VOaju=TPB(%4U)#5*iM>GRvL$$CGmC;l!8{xpWa%_NeL)}a}gSGob)qQw6_AlRA!tjzzR zr9`ir0#lm6@#7`^6pJMx7vhidaDc4XRopD1>*|pA5W$6*kV%FGi&-g2pEwvGXj}@A z$nL>5>$tt>e`cuNunf{PZwn#0rH(c*wx{m+p-mn|1x?~thZ%>u{d|C&tpmU9AZ~<~ z`bwDU3)={F)&YHv>;|RvwZf4Sz?PVx7?vR(cc3DQi@PL}MbjWl4F{GaQ$RXv&{;M> zU@&8f?p9t9zv=XFZbQMCBG+)_xyu(}b5vc2Oqx?b9njh2<% zZWo%1Q=Eu_zf6k=8r>num5zbWqHq^QWELS7HwHJ#O}wC8*lRe}6GWRA;ReS&tOqC@ zmYUJNd5Xo)(k&!Y{8n(Vdynqs5X`5gtd6tt8uh(RcY)f`mYk(kyH$hMz~0*oq%cnV)xgc3m$s-qe~3 z9XesFdRHAzTt1vOKf66q+seOc8(^CEDm6d-rYQaS-hU$j+7U!04~T?c@{Rx2!uVet z=08aIx3l~=h4fe3{8y% z)D9*Kz38R5t@0xiJZBWLbg%gh$Xk?m<>qf_!ofD6!aR$wi?4UKCvv>)ZX`lSc3nY= z17E_B3e8J4@b4kGeYvb40(gDd8X=T6aGt@_q=xofOe2jx*TdR3TO`Az>;2ud^ArnK^n*VY5v2Od zs_39e^OMI-m>h#uzn{m2#XaR$vh~>rM5}2_OW*u3rox-De->2bdJeq;a*1We(D$nA zmNLGG)7sfK|KJ&fk!cBv^qRYQHP?5K&b{6`sjKCDYOvO@l5A_{ulFTkPphM~Y}--& zRhE36e!S{z=HX@Kd4)D^Y?-2-^(ot~^@MYM_07F3BD)O@!j`ZOA~&MMFCl3?~lI&4vz+)((TBHGNM^5QcbCt6}2E z(#&6l$)MYEA8p){=yY2g3``w2lLT}>UF^>0sLvWT)YwfUf^IUkkDNB2wOw(K+cAsC zS7)JQM-gAr@eUx91n>>uPT`1tdMD*$tBoSzi{b>c=5x2fcn{X*L;GGR4bqxQ!m+4-Bl~M;wXmdaodg)-Q0JpaP=Npfl3G?N~2~ zj6`0ncfDy0K}X!rKYE%5f)<^3@p4#UEA*55`$PR>>0~O<#o205;p=t1O9WJ`=hRV+ zM%AvOl;v*97I)Mb!=%!bdz7?@@y)0hCe$0%~^9fCiD36SmWIdTz373iUeJh6Ias4~fv1eL$~E zA6Z+jKRws?n)*MKmyfD~uS;I&+R9z?OR4b2vtJ{{{m{8s4;uFL1~OoQamxhrN~!?tyXjjd!d6*yEp8_qRQM z+=J>E0@6lT5J5l)|F;PJk3IgIi8dN9ZjLJmB)Ochdh}VZQ8LZ=Ow@i2>E-tVlN|t$ z4iPC^`nZF>H0q*DuX0A$yoGi5UEYcp=B5Yq;+r(yx35H9NUy8EE$oa|Z+&lT z)0jfhFv2oRaA4j~k$MWSnB2)1|2dItVJ^>EV38n7rNDS{^;NN2g(d6*7DWQ8^iPna zut?WXx+G?#NY(g*$6ay{%O#7n;OJ2tE_|mm(wXYLMtG@i&37-Bur>8Ef`$Qsq&ogC zBYwUG^YiXQ1N-|@N@%+%vNcy!X_}5Z}xs7}97Ug!>4 znUb%resrFp7wl`aVIv4UrG-r5Ly4CuM~`6^A^8dHX?C+KOj9#W2niY5^|gGrI3L(O zREE55>Y$4LM6-G)sx(i*lA7M|yqZx`h7z2&H7>7Y8T$fE6Pd#4Erb&ur+(bmtAjXqGg@YG<1&#wl-urD$7 zVDEU&De|Kysq)}LFE=_qzbtA+k%7~~;n)dxWHSGP&5{>4X17InBq@GZqW-bh z(AmvNN_0t20Dkw_)WjXq-*V62(qu3)u`=f6#TCgjbaMqwl`quaz1bjqPh{IEo0g8? ztiV`W?6H+(O@G7WGZuY~G~W0}n`cXIqdaxmAoZQx3#q76T95H|$o}q?K1FTJUTe>k zcFu^5N$x^rYV0D5V%A$Vo^b~(wcMMbCTahz9fLCJ892CRzpnCvyswMtKdUqYnR5zN zOf!^s8q<%=PfS$4uN)F7(tbFWuRDo(q{zEzEG#6|ij<~4OytzZ&%nI66@R6Ldt)yv zE5>;C?5W;9gZ)X*(*Sio{1h&t*Ne`ODs%tTb@FN|qwX8hf+VUMIZ<10n@L;l$4p=f zF1xNd>DZWev%W;?Q64U4ZLBP*-Yi$;86n~zgSgGb5g-x5xD9*ouBd*NhMiwi_PAsO^mevbH;s#CZZT7L9Eq~F8LjD!-smWG)0``U zQ<$x=p%>>My#A%%_KJNeUssC)@toE}COSn9|Fm=eX#}AG{mT$RrVu83nao$2oUXMm z>?4lq<;yME79a9{v=*_lJP0TuCMATvUA1r)4GibTCOF?_+s@=wTpT2}r9ao6FCl zJ%F^%qIS$10gc>NWP9{wi7L2PLXoX}{D zg;8`YSQJANfkeo4#!vu#%KL_GM+Ssr0|d{TaROTJ9E70rmr`oSCqL=g;_Ze@GSS8a zmr1V}fDs8!gp-m$s%c%cBW9!l&-GMR(2r-;?^~sfnyKGf+p_6;K1IzKmkvxT53%Oj zs4NGc8}P=3(1CL|%hR|-XY}1yDpE&%W^-6Ie}6tP%Zm|+;bh`PetJ=kQ zTlPG-IDaIY`I4H!0j3;FFJnM!1NYg>@fT<(I#|^3@m<~3$e2^u`sgzT|s>R z7uyDvqiULLjF5`h4+8U>Lb0;CD_>!P7#sQwZZ@t_m6HAOz#7U88Y_{)X3sLw1ss>v zKI1tEOb^2Sae39zZif)h$^G&LONNx! zny}O898%qf8puq6#%TGm8kNy+ba*2+roh{p?(xp=8eA}KEX=jQ10_Sy)|6>GwZ6eV z-~$QycfIJ32NzKR{AKh`o5RLbYaemKTd+i<+20o>4CH;cmRC#-{-i0>JeuQ-((UZX z^3AmA>_-u15Tx{nNA1mC_yl_CRe@ZK=&;!{!r&gQiuMU4HXs70r3yi#&^v3xJ|y% zPb}20(uK{hNS@5Ox9p+K6E2G^U?)NBN2R-v>4b`=xAu~Zj$bTiw}0fTm{J_6zd7d2 z2niCF4K*X0y&QEP7u|3q>R!A17qWDfyO@uYwiukm&RTWE5KzOevI$DocDiuIEHf7|)!tXCxk=X9O?4 z&?V#gA5NJR3N7y$VvN?3fIlWN;;tCTIm31xL1Qt9*K(@8IE`QyUdWB$^&O~0z&#nb zUtDsIb5J+1j84pR)N2>#TKe6~1B>{9*hlx5luPsPVwWvOGA&$`y)7aGcY;Y5d_td5 zA?s9Cs)sU!cF3p;m*d=|*D#wtQo=}ug+JJecK?Ju`D&o6Vv1tVE)yLKR#IM3AbT3t zWrb1ThBL~1-62GiuTxutAMb`SHwZKCij_bzPH5zYi5_0#BfQi2nPlGGueStwIeqXY zHD+riMLZbAXTu`TZ`d=gFrGu74xniCi+_cT=Y6+<>jd8BOQ;>nAY{&qY2vKZ{+>XU zur^biUujbK4UAiSJ!i=5$U4EeZLH!-{)j%Km+%A&aN<08&gm#5J$xQk z)NoHYo-k34lWw*&&CH3f=dLxc??T~u!TB0kFm)Vf$cX2nw%%RW$362JF`>zF&3iUp zwz493W7~>(ML}U$$<(;#jtB z+QKzAan$hm`##^F(D)lPlc*G=a}yQg2u)`N8ee?#=r=8r^vv@K>wG| ziHrR=f=*5ir)yV@0ZLU)2Va+_T482gCTaQneLPh;ohBPo4Ebx4zHk6meM+H`e26p! zc)SV9fRth+0+HKCS)3`(IL;VRzmtbMTmkoAW1@-K1x-I? z_oGEJSV4{WhH4|QZg4MvA$5wML$!dPbwUFd`N7*eRc2Ble{C*+uRw9{gLI#lBCex3 z*026Bo)`#nF<&U3exIo6$aNNPX4&9GBr<=dQit$iBgG?)f?}pQevkdtp1RV#O1A=@ zDsDz#8V+w>Ym1f&O;xe=^byhEvqf4!fZq%6#CEPrRe(H)@~(Gtx4VwBHK7jdHiviJ zP6#4;=x6(2S56|yn7fkG2+18APeuhg2+OJSPlub6D0B&NH0=adObm?E@3ZTai)zgf znoa8VW_#SiS*R7wa!?jd#I8RFlvm7w5u8GWN37Ly$*)u^xg5#T&12w?=exE22sUv4 zJSxtWhr(SU+MP_nU*V-w+SmqwqkqI6kMTfK-2OG#VcqI`Qa zcfykN!CC0zo`8$W12x61GufncKANe}rg_00hKoB=f3ivO%Jv$osbz$V&?E8Fw_a|M zvPAZVfiu3LgzM%&C*rIOd5=23^(p~+bFaugFGdfpjj*@*W#gg#_7(*>0upyh`@U!o z@*8?>O0Gx8=iduqf8zabOOTEfgBkhN!h!#PL|%J4V_@w4rTGjz$@R+$$`mET&;-#u zzSLaRwAKud&{d-vJjh6Uaj@_aG3XCc1>+JAo3e^jCeay&oE(_Cm^$Ep`f5o4Guh+I z@N)<@2RcUyNuYv4ce58<7?lp|4QXGAYgS5fdVokRhQ8vcLY6-=TUr8kt&mtq4ea_XrP?s)Zm8uy{Ia=}6dLbAc z4VTdTo;a7K3h>kTxraVF7GYIVHR7@wRZg$kDaztQvZd#-_U=pP#Xjq{=J$ys(qP4H z3z*sd7+j}l0k+!{Gir1K3#K0;m0J#&qaC_(4mcK#Ye7y8(Go(osdA$th*T1cj3q0= z#4Pt>cqp^;b=IWQv7A6jdD_9 zF~HrbmSDq%-$HS@$8+`aO(Nj!`MlM?XFf-Fjpg-5MWgchjOi6V{>|rxfN`ZKO3#N% ziAf31268v7fNO9I1K~7{ED|zCcyUN?C`6?b;rrN@&!ApvVlwsO0|pesP<%V4GQ;g& z?wp`)41amP``#!4ThvsPv6>qn;7G0Xq?e)Yq^=gdQh4Aex9nQn);*}|OszxAx zp|8i>UB9jG)gWTbl_fwx%&bdG#68pw;Nf+{*d`M*w{%uHW)B!So9hk3SsN()x!~F} zqvP85>Pgj0?!qGb1I2^!W>os#PcQJdf54RmH8BAChizbs_utZu z|8DXAPo(_IKWG`)*jWBP4;-f;X$)-bzEA)>o?>#pFqxX6Ur(9ZPWkwV+-O&2EE zc)9JZqm9N2A^|qt@nwVE3eyRU6Iv705=a%GItM4(KRm4uBd;Q&r%5JP$x0{SDz&On zkG|(LQk_$Yp`Y_3rHo7d5^`lAOtU~9A~1roW8>njlVtD|`_oEoEC|Qm9=2a#Ju1I4 zr6we^(KeoAiUtS6peDHjM{2RQ;663Ctu4EQOpRdcCR=ZA1>(W&i5ZnoOeW9UJAS3V z>g+QL(GwwK__1U~%?e5=TI76~>|pJ1>|m{g{38bkc{>SZlKjuYNweqGv_JjH;T1Bs9+QU;cz_gArelP{5K~cb(leTm(xx3jk zP5tHp)(m@oRu2FAiwJLEek-0aLlTaHx^(6o=V&1KQtWQzqi1yg*+g;- z_ozEJZM1~%@Z;LVY3tU}SHhbpoVR87+!v3uJ_2m5HhwfUSeL6Y(;SZEclVdi>E{>S zv>q{lJ7RuQ$ycMYI;Y`!S6rQwwU(eLT)VZjGO+m_5)zwOcmSsx05^?II-x zeM0M3=3>M1(R0DRB~nWQM;@GVG*M1&$UU0_5KshdbcRCfK%Z%HxnhjNtvzFMQn}c0 zi>{Zd)cZhR#UnXiZKvElaXRxaBTt!diT4W4P_9cblq7sTSPYI;`yll#o-VtbQ7y9Y$TY zh_PY&xwsM+Q0p&V6uX)`D5_w|TED~niBsJoXpEPI*vc~8b&44waL6F90b#s)m3=){ zz9)4v94<_ajD^~#M(uwakp1;%UvMRXO)uf)sU1F zADiZ{3LF7CE$@#N!Q18=&xegEj&7~0Du>B@EVY7Oba3L@7fhaub44uBwPr}1!Kt^q z|Nb-U&StstK6%ttzO1i&&Yygv-J%)q!%LoBE2!^Ru1UuHX#k$*uTBrJba#WQz|yPe zq#tRf?91jM6 zJbNe8Pi0jqLJXETDf<1C!#P`Y)sK?obD+ zQnVxDh}m#pw-*_crWE|@y;P7>F@IqI#yWvvCjXjUc?yb|93 zWa&lUKV4j?&+~Z zPuuC2NOxvDyOLT<%Y<|P6oi$QoreO{G3X3Jq{PKwMHur{u)MWv_$060yD$krgD8xApWwr?SA}bU5O0>blnB81BFUU7>_yWzoJ{d;IKM8HS(i zeF!!7y*$+*A}!6n)2Zludmq1fgRe(E$9sWBT0V08Q<%^Z&byc z;I?0NMrvE5)AI%`z=VjjiIl4-pqCSu{d0+4Y@oz6!UK^`id3v59uNZmFnGcHC&cXGB?qp$q3>{n;YjZ`e>zD6QTzmK%$LF0H;*`iFsjzd0 zhZ>p9bhVpUj}=TvMGUG)Nqu}{*wd#o61mCo92msWr?3{v|1#Yoso{#(AUK<|u*}7o zG3cB!zZOOoV?6>r&pjf+sBFL8pgv#{Zu8czRWgW=F=eG0Kd*rzQeW)&*m;Oue{&#=j=SD}tyetT@7ApPlVFOS4&yoh(KL%&abo&yMf%s0z@Je48^j`$Cg1UZAhrU6 z_}}*d{xh!!ilhE2_VeVv0++kcJfnl5P2fbpccE z#+V+bIEo#g3&EKQ4!us5qf^_Ftd|L!}||Bkec1z9$F4;K4E0Fnx2&~1-3D(7RC zDlN`;1Ikx<9a`H40h;ZTk1{jnuSs$_$YlJK?^lle#UvlwG7$N=5vL?uE7^cPH1YWH zdw~b`JF~iaXjwF$OaQf*6H$W=vi@?>QY0JO*l3Y#R70BwzvT(En5d`l0C56?^fZY! z2a@Be>-+c*e)yjf=sG-s?J1B9pfXz((m9W}bce>sdPh4{ko^G}I@c4VS*I&6Ld)m- z5q7MM4xW7uDsf8@s)*B-1O_#y#hWSq`UbG2hog za#`ZkEk6>Z7_ljD(&WXL#3hrjR~XYg9K|*CQMo-Zd;Z=m{1ZxlgRE;}jAaT~Jf;Gh zOL+gKHxJM;`BzJ6+!9Dec|( z!)@V_h8dTr2m}Ja-wz^)5CtWWAbKbq{tZNy&4;z4EC?P2nzi0X?jYrcCcXSaFIu0= zW1po_oAX)9;v`};|GZEz7JjbQXMxCQi?Dt8!#WZxm_%qPumZ2E4t6Wpdx%CvH{g)x z8R8l48FGYZ9(m(kB}^%p887?-7&mk|xEAO-$T}DgcsuC3AElNcXd80# z>3w4?*lRAzu1uCVgsa}R@ zdf_x2`OXMc5?L60%1&iz=KN}oaBCO)kcW)rZ zb_sE>2en9&Yda}lvXF&`6`u3$2O_gY9MXs4M_6lqi{y(1Sd>#5JT02m$(dco&nL|z z?V9P79M;h*lCBj|_)e-jHevX$re$7Ske}vMrnnJf2rQZlTRf$P^vYQm{2<94mv%+= zO9eP15J;z_N^ohw;1W~C=wddb)1zSsbTAY)`)!qW2&R5W;AkZ#4`><1`vGFz5LC6? zfv9&3-E-!BH`(re&#*}tl=e=KFw+zD#qqtT!1MbHt_|sH9=>N3Yvc>Y9%)cr^5n0t zqV}hg`N-6~P|uLQN&ue6r*qt?GbKUcn-OBFBISd&0C)BLe#yeb?F@!X9{oX{nG}|k z?Z<*IXZz3d9iyt3dz&I`xgrGR7x1+u74zLV=~6C>mO!nbLBCi8uW00* zXgqs%O)!_#8EnN>yR&nabst!(>^j`+%9&AF^dze3H?0cvcdPb)wtIKbnjwB5V(K`P zJzkntbS7D5Ia4SnG(TOp|HP7vWHL$}uv;Lzg!1ZS+Kx&;j`d7>=al6=<~{M+M{`5C z%}G@r#jX^*y9fN2(eX29ho>72f^X|-pf}_m{c=yS#@u>ER|q``G|6dPOj=EmhRbX? zGs1%-cXo~zow6m_J5sU)W7q@)bxw(&FO9@BEHbR6xje1~O7*h)5a z%(^Pn#>$H&r>oCSJy-5fUdHzxcs*NpX>WeC2)BO65umJqT^F6D_{k!>4oU+g6C*hO zp4rKWq;&n;c+6g}L!cWDn*c^yb^^vEPLj7h-z+QQm=}yXD5(`t?(S&==AZc;f!mDE z`+iVYntl8dU-LaqIt$AWY5g=n#B{E)Mkwu zAnkUsKFEZX>8COk#UicZxrE79U%+JldnaptjLql~G;zvz;RZt?!2`9n?>~BEmhZ6{ zK@Rt|6hClF@1)`hFArWRV_>4Fu&|)!U5d*v;eK!%GF0oU{1QJMw1br6GoC$#O$y`S zG!(nAmm{ct`Jy4vLVKU8?&yk?X0&uxv@>lmvThZ!4y+1b-9R&dlcTQcQqptqqtFeu zITlbA;BfM(e19QZ)#qajp5oeX z||b*Yg>Z%Shsv~1!h%6VnVX2W=zd1di8 zj|gRYWB2MgYt@lgU)<~RB3(wuUki3`3|c&B*A#3pFI;H%E-Sd{m=0-g3NI8(12o&p z)_wboB* zFXemjY(S)Fx?98@j`w~5=^GHjNr zp=`l$DeG87u?g(!Bl8rOr7IYzX*+_}UoLK^aA1oYh6bZbD?&TFt}LbHtdnqBZBt)A zu!%JlzwQaJQdlsbyGZtqbfKlK%R5dlnso_hK4Wb)c+qM4>1Zl-Cri80s>*~-o1tX} z@v04Pth0rf@bJLrHBXW`7-ak3ri z3G~>qk}I_8Zo-rB9(`-LlBdf9vL)oTzmgEN9USu$H$08*C_-3poC%^cg?IaeyeC2B zhG+MAi38H3+`ae#2TMiSqakWsTpFSJD00S^YlXP*&2j9DNb(+Ogn9f(-BsE>0R9{5 zeZ+^JaX;kGI?rKM5eKPy{Dkm@jgCR7rF@H4n(X;*8X!k$ z@eRcy&#jn{T=&Imp1mxYM-;y7x(nTXC7|xZxtUxVC@G!%w)a45?msPGzl6Tj)7hJEIdI`TOSPJ z5y;js#6rN~iM&^U%BmIU-gllck!lOISKQf4h2)05rJ3e-ANLRS;jC}+uq20|c42q}<)Pm1-eyZpZ-%3h^SFYY<6PAdN zY<8mTi*PKJsk7(~$6&fWFFVo(!&9GL{O-gkT9n@Q=s1(DFw57zT3*LzOj$l)Z_y&@ z{vh$Bzl|4u^*Fvu>wTVl1OF#i{nKy!?NQVdaZCDv1rgc*A{O`WM%TZo09v;8dU^)H z`vCUlzYC<;QQ+z>P^C~bS-(bdIkyV%{E_dVNMut|6+PEufR5?kZ*I-twW!;%~+)YYzTr+a07M(KY5Q?HGMCvx z{J{t=o#Qr*R$T0ONpQf=9+Q4A=iul4Y1OBgD%ygeGilj|9*%Z`kBNs+&>AjV-7NUq_iRMQXI6 z>hW|i>m4(0GWKW%L2sZg^xm`G2fuQB3VfyRNzg`maqkfh>baEXYa?Oh!f$ z-r|1>;mRNUcFSP}W*LKwl-@vp$Z>LH6x(3lTx^~Y`GJ93KP)oGv(>ft^v*${wSjMB zHOS>^$;8-*<19%sx^3&J75QT4h=sJBTC3eYj2rbKqB7{z)A1j%{y(kYZ~LfJjNv>0 z)^dKpM(}@&xPOxK;^Ibs)pLF8Ra-YMCp}eZOt1hG?*M+U#t+a{ONqWm^QM8NxC{vfcy;6{z!QLMJStqI@?Z0AVwn<7PGdGSVbHBQxQQ+A~p zYl}uk>lKSCMuYj0cqBr?#x&yBAAv0}kL;fxef6}FIpL+e?JGgoptXF?fJ!q+=N}p& zZO(16QX#}Qn4Hi{!4a7|neX4bA$dUX_zrJSHA0p9>IUqCenOJ+G2$)SZsO>ScXL&% z)er3JzcC05br9aX4LEOM^s&72`SyJ))ix#NlMU^@ zOcj-{wzj0-U%mmZ90tplCM$Hs{} zyhEAdjEqli?O~10Rv>3@=#1ywr8jtYJ^-LTy+sN6GxMzJ6NYL3>>;;3xv2>EI^yaT z-|56c;`W&+6iP0Mn>*w4HA?Io$m?(n0AE)WED z<$aMwwc`1wQN*(!FM{rRRoHe%7M3*xmmXZ2VLw?*Mn7R4!%9k&S|QPLkK@V|#}41@ zMD!P_bE8Whn(?`~Eg~Sl#Fa1aPU_XEZd#BULmNkmVPJwQ)wco{c5dolWW`17MdRy$ z7`kVhA~@16(<2J5n-Z%n z`W8qHQ)g>}RTYpt0^O%4r1uHXvP0lVpIjMs)Q4hio%guM^O_RIt0r4ptP)(dEazHY z4Qa90OBJ)rmG^=z6-ygX-}Gp*`rlmt*{%N5IsEN5jw_`u{eWd&4=}Wn{GF)(>(JK! zTweLNZeeu0IFNPSzn&*KJ$LO04@ZKZO2yR7ie`<>E<&rZBQn1IX)tcP)~-0GqggdwW|eoAprKrHUAddu8>mb>(hH19a#-AN2h~ATns7FWic>4letYAYwG?HkeKj zZ+eu`Hl(xQTC}vl^gW)$bPlyObw#`zokrp8%%s7JHTkv6p?M8&wN)SAAmH$8NuFIs z03uS~u_|9P0G-CM+?D3Q5@^G`9AB$T7B8X&Z1*I5MEYsI zZ#P)B47*~`J?RGq){&FeR{(Ty9jyF()gE~I-RJcD%b8iTJ+7il8jCM!@+@!P7EDiS zk+`k^zOk=Qg+<(SRgpf)gI~)d<9-Hn#isMsF*50>zA6+85h==KDSQPJc#lF`DIlf$T?Sv; zKpHmgy+8Cuy?Hw03r&lA`^AabzBUIDo2^&#>tiS3Pz5w&12bCDA{ zr~5h>s1PsbO;vamQBsn&(8*p-tYHq#V%Y{TeANXz z+-dh?{GF=bPb1x9cqi!k4qTvgA~;WnD6eo>wx?x zz`GaNXW1nUk}nqT6`uEuopxSL+t07{M2(^Al((o9g+k-z=BhqMdiM>*>b-3w8B}yV zuk&+cJ1fQ+eZ8W2Hzz4n^*MQupUU!4Rpv_KB+Ef-_@D{ByH3a_UV5UMfwpYy$hfrJ zII`f2JBd!@&5~5%(nsRGTy`;z?a#PZVKzz2J1sZr1mxS_o$5^i&Y2H781Cb=c2Xwk z(6I%`0$=K#x!3ew_>JNvS!>L@k|+TJS6q@!lI`tUFCQ}VA_}lWZ*931`Rx+M$!0Lt zcDm}9(vPd^)%nKWO4c4U4!H!$My%JE%{QP1P_ohB-Y+BV#E4}fplR=gCP4P8r%fAD^nAG7Bu18ByDSDA?9IxibfYuIV2a-lulPBuA&ADk2UCw3+)`@o>- z^`5akjiPwaseR&kwXT5ehvz1FRtZ?%L$kd0X&gQ?1rK$n=?>c|#0K?kiAdZEJzS!MBH>NW?pq z%3s50|J%opjXgt}y~u-0$8?bRkSGNpGP1S^bRGDteh(~~dc(S<(t2-<97q+y#2S&n z8RirVa_@E+^6EDuVpa$vBGA1JI1wu(f=TxBhyH{O_ho2?w6@w7wgW<_knna!L6R5JLnVpxvVYZ+cSJl={ zp!HVEie@o&Nz?Qg3Y>*iIrS{yK2zU=^f(;ARB?UlcDn}&%N%$4@um5VJAKYP!kcG* z=eRMoYPhP76SM!}V0^E1ZSGAtN2>cGL2yF7Q%m#3Ud`2FZR@Kv$1voxsC48CO)1N8 zW62&P&GH;>y4lTvwkPw%^4mW*KmPo3|Nh!f#W0jIfXOv4Fu6wi`)dad;rNt*^0OR6JAFN{UU3tMvwn=Uwxn!DN3ok->2>K{h`LZasAASCvk#=ko)OL3m?P zS;!Er{CGff30Qp~FkeBW@JvGAn?Ce$s7d!NGix4Ar@R>Mww|@J)JVyB&*1~J>7pnK zcELv-0iKC{N}w1Nl@)<9G#wa6M_@-nhhv9yM@5GgFCsTp2Z|Mx6XXI!IhY2~FM2H~ zkQxf%0rd*<3h@eVC@1j2TR|IP0fG)J@B7&rM)PGWR|Rb|6IYp5^U9GOdA=j(di&-@ zYa0wX+n9ZWeGY2KYNljS?0kL^C9(@=RQa_4udS_1^O0-X27sk!q<%m09s`Cz^Jmtz zYB_LQYS-0b;lc+f<1JrO2Y~^3Y0qu!uj#q(q@%NPG575!YHu{Wsyd!l6LBtDYjliA zZ^}0h=&VfAjI-vGdQ3Z^o5nHsD&gMj?S^f$E=*#B&!!S_L*8Cgtu8MhdEIPdAO!Af z*I*Ga788h&R1S}JN<*)zISj`3&g1x{hrzS)`(IXG!-WQ*!<`ri`kPkZ1ZN8~n4baeZ~+Z zhVut(b6v~PSQHP@w%5!;v@YJ}CTFW#=wVVqe*^C~2AdQv<(=1lqv$&Ycf|UYMT4z? zbN4=JY!LVPq5-q$XOOLN9iWU&HB-y=mB$?al^pDA zO~6}eRip_WE%t&T&(JOi$_I znvZzKr^i;q-Y_$pwGAz?!a<#_xe<1QoL2jol<>yIg6m@i;6X0S?hR>*ea7*%RoHgh zI=?l=8~krKY7B>W0ePgm^vXt5yD8F5j+QEKf+L$-Z{=^lryYNq@!tks>$sz73p8*M zSl}_!zYYBNkmEO3q!no4sKUSzXw_EuRd+i~)ki;{C2>{VB0gHGK-qmz0h0H@V261$ zw><;~ty|^Ld^SX_nc2m~s^9VmSV>rI_%_43kSU=XiC@7G@s@myAzM_&HwRq=2lMo} z+-ocy*6!Rbjpo6(CnkwWgg8t{1#1&Vv;|lSSuQ&)v~gHr@W94ELOaNTjCuG*Xilhf zus0Cw{bP_@P+>0>Z30$!8qfqU>JI!3Ix9japln<^=o=XMOdT{9Hjp9dtm)oBb66~z zle1erD40`J+47Oo^6U9d{X4WBo4u7KS<13 zqEC)-Q66XII3EdU&Uu5Ak7TNh@8fZq{CK)C(c{Fv1gE&&Ae_yBO#)3Z?v*JpPqtbR z6*Z+clH`mEBJ;IAsobSv-gYHsICivt)kWhTA-8rm+#*XmM#p65^8c{+-tkdX-{byd z>Aee5mtKUWN-qWoy$7U9*d&`|A<2f_6pCW#ARr*U3rKHLq!$$dMR?Ps1f+%{9Rw-T ze$SoRGFy}A=llChU#~}!?A&wDJ@?#m%bA@i=WhwAeIfJj*_y8FRDa!zfPiMr>KC25 zFgx$w`n1E^KNt2(*cM-LUfi1@+N;Sty=c|5S*QE2ICH(qwwh7zEg!I{Tik`VrxO!a zpEz1*$M1crOu5*y*_?JQ*A1F~@L-35xxNg#Qd3{<@U2{Kfa&)?|apr|9 zSGSt$ZLMFrNM7C1%!`tjd~mhylL+nZcbRTZ>F~CE^=AdYJzQw$xb1$gC%&wI%{1;< zo(2^U4*TJC_baA8K`lNV^&;Q3$=|m)OLm&^TET-Mh; zC!7t*bo0WaBGn!S9%#PjX6^#9Yh#0UHP)R@Zd1SiXNFp(-YjU*q}b}^`@b80Y40af z&wPG8G~n?1+b=U+iT9h^AYjLb3!Y?MUp}8XZ0*8~RXz*bzGYd7<3FE&_4MuGm^q^^ z#T6^jJFZ>y>e8oXo%*oeg5tCEJEEhKX79Z@X6>HAwO^c>eDUDqdM~Q?Tll8y+Aqhw zD|2(&`k}=JE;{ge#GUx9S1vzaUhrv zzO-g?<2R*_^u9CjK+~qC?)m=rX4k^bC!Y12Tl=%{EtiJPZ+o;runoNbtgPN zQRiI_k!4bkP3KYD<-@>+I#xsC1(hxj2D9&4Q}MpgzsoD{3(dd#+3^Eww0rV*eYAW~ z?&eK5*P8IMWqjE)Z5zGHzIS-lym{-$aS1J=7Lx|s@9R;fX-QkP8(|&1qeCL%)vy7F#2$*_f!rFElwzP__RQ1yAX1&t|^}9E` z`qpKc8rCaeKQ5zr|%L6nE$I6a9~@=+JFn zu|>bM*xdW*&P*4czFoBR#KEI`p5~ZbZEwAo_lDeDx+m$}!b|u5lpi#sHn(#}l-knl zmr``XQ*cQZyLE)^nbe<5KGud8R~_7UyTqSgJ4fztXMKWZu@gdwk`K$8$Vr zQhVxmeeWbGZwdV=WY6kpWesgJ4Qu!3(OJK=D^mPS`rKbW%F(ZcuE(yX`92Bzsc6me zN8Y#mQfPVb$445R>c1+p|JU8Nwz@v)aGAf~l<9Nx*v*YyrjD;(X#0T5r%Tm-^x2#; ztB>F5w&ZNK%`1=W!1_f3=Vx7fYh$}+jVz;+8g>lm(Qtg1{u`@bc)as`<$PI=?V48g zX5U}3PWvSwqFu$<#hcpAJlkUVw(l~Tu0P)TeZg_X$3+}{Ire4fN6m`HL>+lO@Z6r~ z_xi5=Jo0w!*MB!&fA@^Ra_DrUe&+_7PDIqY*&%LU74eEtlW|{%r7em?y}eOWGsbea z=$8Jw=HyBUTUzY1&A-aKe6?krZJz#3?=1PSw|M15A?GPe`NF)}q`c3{_EL|0QMJpC zPHdF9(x5+9wR%?J>FR}zD)coNXNGNzYPzXQfyIqSjTqawYt>7iX5Z86UDUQRPsdJ9 zdJ`Ttr{|)&pVchY;?R~dOKR8qVb?dkUVWWyh}JJ%OosJ8d@wuRu~QWTPV{Jei+8Xt z599%y$?NBwTzaHa?)){{{}tO@AMx9?9X}r$+|6AHVD?cf z$IO}gbESdfLuYp!Rk?WcRh2eY8B=%Pfzk=Rj>ZfQncpGLte?*1dXXXM3hx*Qu3oIv z=hDZWvQ_`K!S_M6K3x;DXXvb652|XOm#BSc;L~f9wsjv`e$VD7-LBkOaOhISxxJ5> zo^E=!eAel{k;y}5j(I-zk6m*n$A^V9cpE?Ka}ib4=5sde!(~O=zrvu$F|6&@JMkRr zs_x%#|71%0Ha~rof7IO@hni4R?rTXp!kK36<+nbzIs&N6H}5@jenYVo>z(|DXu`xAwSZR#=o%zD#|JAZaL z+jG{=7IWwIGTd!>`c8)&`bwGmUu?L!>&IvN>}xwQ@Jx>8djqcjn(w84^pS0EOTJvD zNys$$?Tw!w78p3}r|K(@^*EE^mx?g&~co#XcPSrmDD{*7}#%)Ij zH+cBFiGC-E<|LO&7_@ zhWl5Z|FfhQOTHNJ)|8V$9Liyd?Qu(r6Y_<)Ap685{v=LIMo;l?^Ha4#qc1O7zO`w= zFS0IKvSfY6@J)+mY<`}8#DtR>du_R2ZT$A%0{@&~yy$VJap_+L=Kd^Co`?Zg8r(C@jNOyr$%Mq`ZC-pnYjXER8(&|{R%6w# zKljUY{bs|ZZO5%RceLS9|JvVH=oc87z1`ZR+8Orbe0w|Y{^T=aHolOi{aKfQUYeC<$eK<`fK93!2+Ybeb6pL=?7Pj&Qk9_UUs zbbMd)KTD?Bl3u<#_n#$GVM(oe^6~N=vi}U33PUS zVYobM!`Z&W@t@^VVY&C!mUF$s{XYw)!h-qSEGQqJ|7SZdwp(1HLCz!CY!G`DC+{=G zhzI&uI^reVuE?+T`f*y4%K=S2|3- zax!FahK@_}wd+=2U#NzuRk_aN2Il|h_@N9RrO!1a=|5ZRh@Ca2c$pQeDbUJUTQU~&CgGj`1EDY^#kUu8TD)Bl?yhsyBMxn)Vc4)$~W(B zcu{ZF**d%TRJ>FE#?aUg!e_iSEgReQ^`__f#2Jjb;okQbwtS4dbyI(7;6I1*;!x_H zg;qTnz1$%EpCMCWNGCT`-%0zQ^}JZG(brdpi1bWl601()e%7<_x^NI_Y@^|7@N8E5;QH+Ol>-g*!$5P8|OCxUE%QeYNxO z&?C)?27g&};liPVZpEA!F?Ml=+&LfR>{l#n`aZ#aV{g}dJ}2GHaf6TU)|YEn^3U{J z7aZ!ACBE7SMI_>3&7K2NY^= z+TXL+*z-reyeqAlTZCzx9?Zgdz4IGRz4&;bbkDUlYjRN zU(~Bf(6wCkhu!((?>NKU^|&2f8q@#mdi3RN`VgKdBPNy^Qzm<0?h+{crVw1+6f(>J;;}TNaogB|7p|14lHdv`dWh*(gOXbZrCX zKbm%Z-l928isUMJNt}OWOKkr~sVjNc{Mj?l-68k|HOEG2$ zo3;(qM)2gytj?YH+2iexd(wHk88^0@yyzrr{=xbb7ky}ya^F$hSC`xDuat46s)Rn~vfrprZcGUWX$@9%!<_vr_Xg7-Jou6P~s z^2V#CS&U7y?VT&-DD*>Iy00_+b^Lj;$nwj7?-Vw@_u)o2#&24@yYr=rC8l>gT&L_8 z=h{S+&Cssggw>V8dxpKxWD8sV*N@ZJlnS{~<5WbAY^P#(X@bfenm)ei`mfIptsQZ) z%Z;zv)|yggN9E8NGmp&v?xd#vf)CfcD0TGo{6}RL-#^~-%jA~JjNAG=F1zKzfS$pX zdK~!r@}c$>Ka4){gVepxzL^ES_^oT3&Gk+WYg+i(l#s(chtGYp=%`=z+i|U4E?zY` zTl~rr4c=Tne&WYGjp8d??p536ck?Ixvxduiz8iV0N5UUZU-_L4Upw^9)6U=j_5R&2 z=kF~L^Vz|j;Td$<2I8^?@qb5i*@d7X3Ew~Ke(8;I(4IY} zePV^8?g~eb*PzD>9UJ&^exHnzAg7d0^f+D0w~lmrvn2#K&`8vFd4psYmgI{Zw_Xd z4~O6>6y?^Lb`S$A;WGF!LMlTyh=V2YEBp-=u|;=CfElm_F2Gx;oL!PSLM+UNZEy}A zLZ%#&R0sOPV3-Tr;1N{f#R?z8NZ0`4MGJpJu3Wr28M=W5X2CAF1WzC%=M06RHnf8X zNQ9-Z3ogPtsK&NB6ehy~cn;M$-id;>a2q~g`x6Z-AsGr06FR_X_))|M781>1Ec^&> zp~-uaG#q|}^abfF7z@8Zc9OeoVFG*)&!95fgbq?iaUx+koQJ%Go3=0-eunH!+wEWy9DujbK#SdBJG=m0No)d3AsI@S z;&)gI$xy1aBn87lI0-q+AQPs-StwN&d%;e~R8ErG!*uu&oT z?n1e$lJp78fpbux8a@nj;Wx-toiZ>4Ho^m_T!XO!VwYPBS3AZ&)e zpzeo^3D^erpj2(1?gf+K2Y3wi>abgcZSWk5)s>{4un2BK@p|Y5!(k`ffr|AdDF|l6 zNyykhk{Uw-Y=oy!w;^(22Rw#KjU*`?mcex>(^!&v!4xo=r9znGh{0^JoDb#K$NyFd} zWNjr$tzkU;0$E$*%PfmK`d|b63ANkv zJFJ6bDBOV<4O8G41)u#WY`85AbkXKAr8KUTaejEyo3&5g4wVaE`!t`Tfk5_0J#ScM`0$MgTj%-1o#@R zLxm{jM%V+IXktB#hC`6mM0|s(uoM1(f-&?l7+^B|0-Ax0O^AmDZ~^YZOUP_yoIz2j z1x=wd^a3Lcg3&MozJ|ka9&W({cnW?N;xN>OaF`8CVLfbvV{jI(zzw(uFQH*9t^q^f zE7%1m;U?UNr_d)3pMd-D7K+5vuMiKTVGZnnn~*I5KY)hN2K0~!(_tgL0cjB97-qs- zs5+SW65`+xG#o-qhmmj)G7ZI-VGPWHLPbVHzxe<**6%!T%r`9>7aT|2ZdpP#Qjf8qgTpL2u{> z1~9=8_yT6bQdkRHU>_WWU*RNNfU9r|?n8z|;vEzKEmVX?&=JDH0*NpQ=E5S_1P9<4 zBtbGfg7m}jdngKJ-~*@$^&tQPp)W*2B76l4;ak`Pr{FAHfN~=wX&&5#`XjLwyo1i8 z=woO<8l7M_yoTyySU*4nm|zHuhpDg_mcu&O4g29&xD5B<1-yaGV;M7094bLAs1MDc zEA)YW5DEif7>tLhunKm=Nq7Y5#}QkgFjR-8&>do79DEI1;Rrm3T;qxJ&=8_v3H%7> zLHYt&Py>2F2#kfZ;E8q$|gZN4G z2mAz=q57A6SsX6GBhXF8pJ4-u z4c(z1jD#f6O=m8H>5v3fX5jZQ7S=$Hne+<`f^4(!HK-2pun;t}8I#ZiIzc3S4cFi$ z44H#(!8Lde`RC&6umhxd%-=8x7QiX^6B^D(7JLfNKw5xLg8{a{8Mq67LDq%zJJf)2 z@D?g8qOD)EH-i;$5FSGGV)_LpE#dF*4tg%d2jCK9{07}&5Bvptmoc9}pXJQcP<{n| z2n%5c+yu=^+76>(0W?~Lp0FD(fV7&wL#;K$U^on=*Rs}u1@Ht)t-}xCEL2*Ltsuh& zd<=%d6Daj9GN2jshESLdN$?nkZA34)2G5|-CVU5uLB7qzTKEcmU#k;S4+m z?Jo3y`|t+Z?52O<2t0%AdzgozDi~oM9E4_j(GeEIcW?|!?4v$719zd~_xK^KhJ#Sx z2jV02gfnmtUO=56i4(98_QM&t3eO?Ke(Hg1kmo1t1tkwKm%s_Q2SpCz2hi;haS7i4 znKcmC{eQ#Hpv!6I5a@XZ9pEjzJB!`VF)m;&T!t@`n2+HN6gkft z6lTLIxCbLIu+D{Bkn?wZ7yRK%I1j}xq9;VbX7~aAh9Z}kA7Bjp1XV7xj)qP!9#(^N zg|P|^palfMdHCikIzjei`~sdpmFu(>a^Ju{F#0CC+`=9Z_6Kc+KDSw8!2`&8mp+H? z@CZJ)VtPl|>g;WXrV zkKbW69ERKl{iM>+8GeT+@CI5I@{_{gAUuTh@B2x)pez_*ADoAQh5e+-a24J{Q4SY} zLK3`R)K97gA+Qp*!2`%z%ui|sy{lwnD)Ye$q$K9l~G)`~W$%eo`&? z4$eZ!l73PH=mYB@M=3w4Ed;@0xDBtMQEBRfS+EAqLZ>o*QaG4lH(Y`mWw9y5z&Q8{ zjzOVv)C;Gee0e{q9RxulT!gw6{G@)c2Y!QM6_EjB;Rrl|#+Ce}k6|)s`L1I*j@eI0BH{b3*EuZvDF0G7jDkm^wf z^oGT-0g|Clee4UL!G5>~^&0p|dN9Kfm;&EGGBj@JC-s82P^^)kWP!1;9C+1_6aqiN zRjAd(PvYy%(p= zz@4e;+yEQEEi z7j8kL9>fP20qfuwI1Sl)5^o?9?m>=Teo_bM4`0Ad@b69BgT-(S%J;#J5C^m12E2x< zpD=#lJJ=8D`!bGT5G;Y6a0*HU;TNzOruDds zjDneP1$2>qQbQOEE5R>{K8JR26mG(w@L@Fl2j9Xu_yhie>?ZVrNw5jp$M{K6@Ex3j zr_gyI{R6K+XZDj~VI=H;(@@ny|G+57983KW45Q!>$P(9ET!k#1%970ZlMg+g_bZ3cEU;M z`x!n8+u&EY3yp?R4_tx2pw8#i1vB70ynuj2Virt-Jj2l&dct5h34cS*5!e7efTl14 zj>1D&Jd!yRvW@bSYC=~S1g9ZjG_el8fd|lV4E+eRU^iqQi=RSg_yaPIqx}#Hli)rS z8jr1^4s?Zya18Fih%fMYI1ewO$OPtMI14Y}qlt`B7zbzI1{9x!UEp(=0zX0TFNy82 z8BRmB$;5kzhIp6?D_}E7Q}6{C4z;FYE7$|K!S5^l9cDnrX~aN?gFR4ax}Q`DOfUvDndv80gfCzN5+=Z>ix}6i77Bh%zrlSdyO{ohp71&R07aLuMua_Z9qKG) zZ37YT3sn1tu>@bkJ*c;gbq7p`?T~jlYYylOC*U6Z4gM?Wci0Oz;0dH(=_hF+3^u}X zn6Qd553ixjYUXW-fE|!~4RHa+z-+hzjn*=jVHWI!JnQf$&_nk1*b!>Ma99KHZNMMF z00Ut>{0MKM;J2(b;4oy{i0?vUm<-pU`X+1&G`WM!vhq1x0>}B9FR62tH9%XF(kG_Db5O9po;T0@D&invJPcU9jGA`i$ zDSYNP`~=QIj?;X0hQ5PM@H@PJmUTP)B>p{z|HE%dtgFs5rr;S=zJQL<=Xch`7m34A z^%8S0yo7Hr(?4+Q3S;OhF$BK9hFu|BGO-Ghp#OE&PjD0-L7f|{UEoK!1E1Ywu7+#y z5(?cS=D=ad{s+3kC$JK>!b^DXHZc$e!4fER2i>3{jE2>a{w{5RhR_=HuovpwV?6=i z-e*q+V;?Y%;4W->h`&6-Cmu77;4Liwld%CUpWt^;^C_|*-Cy|IGujF3q3Uz=fi^FQ zac~;$K#rHlg!7R3Z)8D+SHu$-3aj9Q*Z3CHeuHc{2ElKMq3{68yrcba9IA15$wSEN zr;*CSFxUcRG#aTN41)=<8k(omNa@mRc#ykBT9H8`J%ZsGHPSkG2}?3*q*j?VQmHH& zsW1Ei`?6}J+b}nqhCQ)HnwniB9f$5YkegE@{R)|KX`}gX z8YvRaLy>$MX#o5H8S`tTwlD&w!WnoB)e2~&UT_IYyr+@OFbCGdUib|jL6(BF8R|d_ z=nV;w2yb9&A&qnl&c3ga3KZ5z^Wi9DE~1f^LSyk-m0}vHDlCBF#gPSj;U>&4p^?r( zZLLOXR8k}Lfbo#Kltv1HyHL5bMv8`sZ~*d`(MVswYDg%nkv2lnavG@y^oM&8SzaSu zhl~~Y8$5(;6*ZCxmO+_H8mTkPgOCq2(n$CVs#exWJK-4=tD=#rLuXh3IdvMTK4h(` zk?O)WxD5rXp%0|1u8}6gGRRefeut%yzotg|2rfeQS{kVfl;`H6X3z^xL&nFr0%YP_w>9It=;-8fh`)ZOGqX8I)_Jk^EsBJcX#n8fg+- zfD=tL(p$*$5&i|gg3(_it%0L(3vx8oNGoAbGkgjH0`OgE*@C`@E3m(%Mq1m7HnrAB zNsyxrZGmZR@l8l;q{3Y&ABcXi5RO33t{SNgOoYWy zpd0-H78nmp;XX9_SR;K7U&8m`*B!rsrqBnzg2iwcy7tgW5wI2xLiU~-sR}fOwh#ul zU}P_iv>RUbW{mXFNE_f96#axY!{)vkX-ber`VMsc@L$*kJ@xnid>pKi#=_t5Bn00G z#V;WaJ~9v!;1{?K`NHTEs2ENhfq4;(M+i0&FW@>1>aURs4bVtG!Yv4i)JPAYXp~0! z8h(b+(fBNAO!PJ6jX`%<2an*}fs98pV+{JhWT$B&~7Y$A4j?Il!L?2`wL`(W&(W%(nQ7|jE4!6&;<^|Ctu3_&Rhqw&! zbFl|(h1&Cw1x4oLM=%lljZ0DCf>rwYZ#kw8& zNQ2kW=Jmt~=&%9bgCgHD-XYUQ;vUT2#CU*buxPVJdIj6IV59FeQYRPzCm_#O^npi^ zcN^mY2E%Vqc{|s_0@w)8pxX|O6bkF$I8@n*U11#L-^JL1A+Q88>}LE!a~J|Y!Uc%h zLyUmS@EVHjrGMcU$g+9l0z85;w^?Jt1IT)Z zIS^{W=dc&9!o<7y0o(%Vo<^zwgW*>wcpqN{BP@YU@F(PbfL;&>yCCu*V*#eZNq7$J z9}&-BEKGq~wZskfq1<7w=e@X9^}&{)Aia1Cgg({~8WgM#84zwZ#YKk(MVKN@L7{r{ z0P!sc>BA4xQY_LK9w9$QRjORsyVgl|@;Yl}7Oqb)}9#YvYYHgEnfq&SrE)Vt2gI6IwA zmr}Lz^^OW^)^slrV>X5JR|`!t8;6*pWA%|Pt@G6HUQ0PDt5nHHWl@GuV_cM6kvx7p zU2MTgLn4Ag&8C=8Q$n<3uzm1>yJXjked}R+bRVP4*`yvt^Ucs`o_}n+*df}})v;V= zj1Cp=F2j4QW#l$`vSX}aP;8jd5E+WYiPpv&4XGJF-itYut6$&UN*>FZMKp4;LxTos zFYKuL{r8DfkcZk<&o!Vx7%|S?nA!ID`TN)xf5YA&`jnUy2S=nO6)V10#v^}s;a_%k1=boO)=dD(!Cws}Y zD#6ZXBD++l3muODvxZ)`%e_43%4NXYq2>MW9p9J4IzLuf36+#)t4U#hNSQ~GDvw&2ffU2D1dE}DQP`7`x+qP`74+VS3bLs-O>+P2nDx|8;=~=SY z7I^Q(B>@1$(*HAy`>@iD}5g181eYd4(mEPwkOOaZT$VJwGH= zQevud4Z+3z@t4-oZNGwHuX?qw)%`tustQhOJ-kIEWqiwWyoDiE8y&GHcW!&bZ2>1w z9{Zo{QASy!$>QBYOTK*e>s5nDRl@aoJJx|GOLK}qsz!JVJIa`qi#o*`RX^BApt#EZ z7z}k!IbUIWS_8KkiiX&ZKdQu6uWlPo)?K3O#;tmFQ9y|+TwbfHU9k6Hp`Kzrm$3&7 z^#ZI)q~08Es1jexaVo>&#M2T_IXbW^HORS`+mc0|E0r*i$`ZCkiCnT?JtvDrg~k{i zDzcz9#m1VVf-I&;W2n5bkmHZ8p1kUB*f8~FjnS;ESjURMVlD2x!>i)6YB>t13pZ(! zn!4p9j~KmKENR59OD*A}kJ2i^O$o*9c6W1afhB^PgJL*zlj~JBW{Ta~P6E^___Cuo8&@5~TO+Ki8GJdi z4+&}|e1&Hh5wWHiw~lDk$h$LnE3U5ISDfMi-D(9@wc;SjSDbP!q*RuQQbJpoY=kJ~ zE4opab16q<&IkL>0ZJ4T$%!CVaAL_GD$kS7$9!H&M4QY}`bhcufB^57x7T1jG1kWz z?UgCEbZF|!0X)f(eK7UKIovdglLGmeTj=5NVPRfh{v&GlT-;H;a(3oUevucSPMIO4k6ha6oIOdS6o)d-c_zoqa95Jr`D2?Q7`TOIr+_XS3i{pJFMt z_SIM3imR*lHS}#e`C4_!Y>G^%Jor;uH>gUP;>5di?WKG*)mBQZIJ~T}eKplvadlHu zTi&_?aq});Zmq80sk~Z&RJLCo!_;vlmHIms{|D7OMJGAqnzE;?`g&m6d%>(KprgsWrCN=W9rd`r@MP+IlG6w5j)HsB0$PtGD}FWBC@M zHhQa8X;4MEA;8=4Yu)n>U(dNKi}!x0uNbM=$$r_mqNi z|Aj5IsoLsg&y|t{d6284TZGdh)PM2T7;KC?L~xJQ@jLfpT*VHr>(qo zZ>8!IFB6rQ`mN>F3ZzYdEdr`ENSj;P1gKR=wFGsdPdRC~j)zn`rn3aM-b}S)dXl4V zQmP%(S&&*psvT1n;ntK?JC>@ry85)0{}+xa*Z*%EQx;(JtAFB{P6E_6P%_?bTTqTn zf=#9Yk*WEH#|6ROHtIJje0 zaxUg&`>ZY&s~4N0P}h=P_A;uH+~n$3pBIBFnOph3Lth3J2f*TXG!MI?*m!GB&>DEX zOu;UjR(mOx+Mey}(l4G0dNi<0j>Tg+FBW#`Qcp!anb>719`P@7r9R81oGbNNTps4i zc2!wYxlBS{3ac|qBGjlQxWxQaNN`iaWjwfwaLstCf}Kl8r&LlMY{Gd zx-1TzRQI0hRJotRf|CHX3ce(` zV3s2CQy!QM8;Tkl;>fdcB<61kWyJHN;zje zWp@{)d__0vaxUel%q3Uqs$$ByQqLunCAGX*aoHYuzFw7~a?Ut7H1*{GqJeT&S0zUt z2dOXaIoWA9ugi|atreb&JF0idmAaPqoGW#|D)qTi*RuaCSDH2{j^?^789jyZbgC+M z$(6cmt!%vcI-jTDr&!rn0P>paRO#SrDdV-g+77Z*MWUAxYy&Xszu+@-j>dS64|mH|sKSL#%&s+8|ssmD^O&y}XCxVovn+}ftJ zsNR+ka9!Q{a%->U)e89PYLx(W3{z(lQmMaF@qbXgQ*=^|>Qq+mR9s!Xul<=*zEj-* zYYg`l_npd$KC_ldb$x1$tz~`frPG`%b#hd32CM#(wC&JTwVYRiuuIl14MNmLcgdCd zmXfAiX_`f;)pE&|rbd?Sz}U@DF1gaQ%TgJ-NrD_4)KSqT zmF3cGw{P3qg1aI|ZEY`$uap#0i|`WQy@+sYikArMv$(qYw3SaWm6d`iQ%+^2Aix%P zRZfvMx3URP+aT2varAbtZvuZW)?YOd#~SDj#VYo zTaMM`60bQ{)pcpgv3e-yF$L&l+l_&3)se(VO^($=g`N_C-VI7Uu|eS>QNHZ%nu=Av zTyIZY+jKA+Vhjii4wq%QB*1MKsq?iiJJ~_DYm|q7rSKh2mvQR5u!qE?%d**bd3kX7 z$SZm)txn{K5vms9a{7@P5pHU@q@dhn_()E=Y&lXas*VpX8*%rt9@CR9NAX@txwX+{ z+2^I0dxA2h4z{HUJ%5|iWfpR;)hWN}rgTc3YpdLsgSgzr>Qx1`3^zqm>SlFeR}W2T ze5%X3RqV33an{~@no%{6xvV8pD?!%8x;IX}67o92L#8tIN;paQXG+*6bJx?H)GOg6 zL9K*O5k7K_s{Zil(>_F~)$kd$U1WI5SGt^QIs1gS@@fTqhA!q`&lyXfq06QgVmGrspb1$jbUpcFFxnslGIC4?-L}r~weR_&q$jg^FQ*NTujHQ}wQf{JC zNp%x_PE@kC%5Kvwv8bxv=ild#A)GGMwIeX5|Lw?d{&$$&; zSLt)%Z7=C9L+Nwj?YXqNa-T!lUfd#8HrHEub#qfKz;>AJy0-P{;%W_?1gKR=tqs(1O?@h#+9o)a|0fDK1+3KioXP}F z<<$!KT$DKF9Mx^G#&(|*f>UA9b=E?uuTibEwXn}2o^s04CGX`tgNZZEROKvvuEl&y zQJdZ+JD7qpzO$At*}=5SQY-dPgxL;Z-SU=g+d6$YFjbm43sb9>Hq$%HQ4JfP%V4)2 zbQYsl$NAyZF54#e?|FLND8%qULC$p|m1p57Pfql((v67`%LjSgsXWNm<27+Sc-tY& zi(T zHd7KIM=f>8ZrReaKc-HQy7RrQ6;qO=mf>vz@*=~nHQpv5pXJpGq)~u-(#qQ;>_r0) zS*tWku+0i8=SZV}*(9j#ka`hv>g(URsIv&SPEEawdJ?2=Rq9>TS&~{t>RnWp;ntee zdzh-cT7fhQ_%|*pYw)jJRF+_Kuz%#DP7>61@HQ)mesH-=@J?JxNkGEDg@;EJ`gT z4bCbHacfW-TumiFtwLHQ{3~abb@+GADvPjrnku5D)zNGs)V6S)we7=>8O~`H;<~U< zU+BIJaoudYU+uIG@uh{+Ld136RLixmL|ncN=ZMd=$@!TZuBYE>akeFe=e3CIBF0lm zkBbr4J2gBO^s*Xp%@}(s>uEXSdX`}?=RCbPXy6~M)r*4*Wf8*bwg$!-*@A2J(b~9} zP~Op~4KtawE#(`qwVk*FTWh}sTgs86gFfCEE-n&p&62WZv;Q6!BW2Ito_82(tuJbj z(x-3E6HTP7Spy9QtvE~3>3C;DGx-HkqBfNl2x=y>%G!Z(2J>J91qhqw=fx zdt5LN{Iy^9v3Pnb`iaN?ii*U;?zIWV*a$Rr{Gu&ukuqlvw7yPADqp_2LEKWVHPYxv z`2|5(A)J#OgV_+OHATw}=HV|0LC4mi;$<5gM4G9gdtk>JT7U6+BAORFIL08QOBZL3 z5?bFJ;WA zbTwV$@AO_HZ414Tr$5Sq*E6 z3*nA^i&*FlR++Z4mPguz4A91!v~l)Q+Ay;zN*fzt&<3<`&pUcd=4#zL)a}?~V2q_{ zSi8W^9Rnl6s@LjjF!c}6^Kp0ocC9-059<-tzC-`u{t>-GTL*Xka7fqw%{x@n(*&ym z{-IIEXl-+Ao`Ls0b&a626O56OT0^vWD7H3KaRI%!ke)ZoD{@}(<0K$JzBW|Klc$*} zDuzoOB{4wLo*kR>PqU7l0wjZ>rzuV=ypLtKaCTDyu0%r((Pk611{*^3JZfG$*c4~B z)s04GlZkhtG8jT_f9x2j6)&lv$Ax>EB0~*kjKgTDrK_f^DRt_U_Igqf*`Pt%McP%D za^_Tf4ZDoOg`0_|GV$UrZ5Me^DW=u7W?LlX&K)4zLwu@Onm5I_>=Y>4Dh#J|PN+`X z+$2n;P0&Zj3M+=2#Q$xtYSD^xsbXBYFA>m$*dXNC2YKnzqE!+4co80A6}yW#hB@`2 zp~O220th?S{+5SwrAmrdRF*qZ)NhHSN7aguHViS)V@;$|r9^M1a8d5uXrbxaX)Mj!`+o3gSC1wz-Uw~3Uwk5;wTAvV=V6I7+orp6)o!Tt!mnex9TlQgFChE zpbg=5Z%ybGRjpP#*vu)lZjF|5n`6y`MLiw{D1%d{^;)gNERrO(YL&GGK5t48q6mH# zZB(2kmLZ_Eo`YjQ+#A!`EK^wM;}#=9Ocu{E_H+t5)*TN2w;-5X;&70QJRU z@M1SQQE!aa5tds=hnUP}L}^)w5QfBo0MFHzqc{_)+`Xy-Idb^R(UJiXZ6w~-tZBVQ z_^pVGWviF5hziB|1+j(d5KcTII?JD9Vx82nV>44+WT-rftSu4EvUat5LwEt7!Axts zwnQ?Uv#Oof5+Tc{7p>=8B5sAy(on0%2vrq-ws(PZthJUCp)EFoH$aC+*n*zT6SLyG zN`Mf9!8QR^tET#!(rfk_XexK_ViiXmH!*R4^bvEF2q-qk6w2wHrZ=6fE4+wk+}J9@ zFvt+XS&M9Hr!$q*3Q+5y%#}(=Oi6!f`7 zoMt8K8mB-3TcEYhR@T3F>LkX1eO`~Fl5j>0Yk}y&+U~7ew3dfJTy(6%A>|yM(kA%= z+$+o&9%q%CRjOLGg;?;kY}UTM&7PsWC|krb270KL=gP_>DvBwJ)uE-NRIs3&|3L7kbg5~Y|jOe;)f0< zZJ;pBVdI_=|N-E&2I<#F9+Rc`Q>aYx$WSjh+jv z2QbK0f)aA=ag0?g;l^O*J|>F+UBg%&MBpYZBK6_C(=UwvQeI#$UT_;to|g4<7!QaP z5uG1-F#{Wf*unfLPHp8D=FKZ!dgoFqQzmQYpm>xeytP<8%HpzQA+RWGK~@0#9B(v5 zvdIcX8Fk2^O~z3EXR^>D>tdc-Z5d(qD?$P8T2)@0iY&fC8!Kj?Aj)x}SZ){%7OW5x z7tGHnA|jIbj5fzG#~9GbjF(G(njgRBXNFoRmoxXo##!iq8r5p>|60|m$v;W@7nkmRp-KV}c==NlPrNmC@3=lWkEZ<;rFKn{DkP zZy812o3)+1e6vO$I?=WArH%S5Nl9nNOt0- z=s1rs2Y+H4h`qZSqYQzu`luM}Yh8=-lXX=h+k9|4c6C%iP`8y9Z#oPyu!B<-&yvNS z^+(ZW9ou(m7tl4JIpzrH(xqb;(eZ4K_*LHa@@v2#)_a*VE5V7aX0~j2toZ)3)!!ma zmRR}6Y}w@91w(^L9TP_B2PwhIKbAK{$HZDNA$uCJVTm*hqVZ-68t|8PhUjoM#(b(D zgmKx#wvKMj_p3!?jM1%FPMO$xi`Ov92Lk?)F?3EGHznXEetua&_kXn>(`L=e@_YVRgZJvVD7HO{2K0V@V^DDJd^!#8paUSITFV+O<=8|GyX4ub-lx@`6Q{kIas? z!Objautb*^0bZ=y;#gs_M6zxmtbHa{P4-!t0d3p(2pJ+KVu7F_S>ykQH7IkoSf>-Z zwEq`VX49t1bio>;iU?P>?K;~t+c|^kXu)i-UL>F7zi76;?Q{tvTn?bD0V%tuT zC;iHs0HT~Z)_P!}OxTsRMx8-hUz?DSpwkD3$VV>P)?tblSf!YGg@M@6=(Uy@Lx@oy zNw1h$5x7+1a1ZtbVfGD@vNzDV*HgbMi{^Ir9V)8S@Md~RTrjKMU%#%l%ehp?Gsn6MDbjV;LGvBcd zWR+$xQzg^CSUOOVn4Dw8?-u#IEEHMd#j5rx++gl1&I_|-5fg`4&xlE!wWKa8G>XZT z7%Zk``9OeE73BxMp}IzI@KRWM$(}q=>(5v*4I#?PBue;h;@SRn6r^ zoqW*4JQvNj0An#d+po-@zk^8}r7B0y_CM#$DgSw}{SSHbcCntv2HIU!KEkLX&S~T! zEtUuPBYT`Mqd7_}B^Lo}If;tK^0G#6s1&gJNrEH+1A+RJN*yj9`P< z^N8erC|e5a-^H&k2Pkq~Vu_E36GN2a5K4$sQf&qK{54cLb46&>V6juPhJ}heK3#0i z+^*tqfk-Nn4PsjtT9NV5+$7f3yzkm-Ci{W1VnNlGk1>P`(h;_%N-bI_UZq5KtNKhF zj!meyLlJu|L=~L6b!(?i(#uuI_QxZm^aGrac`f=dY$f)5A!gh$g!w^<0Pvw8v~isA`t9Po-E$R?aq0 zX2{S*EF9SPh!exXTD8siBdcSkNT)w$&fJZuPF|drDH9PJ8&kh()#~+X=&IMQtE;W6 zUB7O%y49)@kbxHH1c{z9~%-;*>;%1>@7Pm5wWMi!f9!Ma$fH#A4SUp zjp5>eO{!K+J|**z%(5;4{FS7Ow!6qO$tPyDYs*CvWF?rxSzSbmV_`9dtcfsT6Ze8d z3MEgb{z&@lGiMFN4uq|`cz2`6WE!rj=iJJ=OtP-$#C&XvwDuUo5d z=a@!bL@SwwL0C?#+G0g!NQq1ii(7M)gyyg?)`sHPm7`7s=-5BmPQy616@QYvr&K-J zPt02KA*#?cRL7Y0*NQU=^+7BeSv^_KA>jbxWLlK;BvIrkZKrO^d|kM(r|Y!x$&b{g zjeHRYX5rkJ9?s~Iqo$j!Qe};tIjtkmHjP%O&@FmEvdR z@PQh9&TDZ78%vj*qx=Ph2QoZ`J zTKE^S&xjim3AC2-!gws4Vuu*DktDD=D$<7-_iuKJhB_&rrBawYLwV(xTyNh0wKj|c z6Io6)c@?`Li!Vt93$ox+YScSbA|*~voZ_M)F^73}|0;{J#gfOblaGluC>6_j1k@n9 zkwXV^GL*BGzoYHvzN4I9~vBhCt$>}A_njQFuoj@^dEM{#bIcrVZt`QtWmVi&6q)yrxK ziIP^^RBs&Qv+j<8wz{1&`zBKBIP4>mU$dOvVoTO2SScP#At(Ykmw`5JVPlxh@TqcblR?Fqn=6IR+v~V zhiXDJsSi%V!~ujhe*f2GE+qe^tnQij?T##O=gdO5-Qjt~ZnV!H>C`zu3Cz?(K{6Uj z&>kd425ae1J)R@?lQm+CrH1TM-kd}yR;lulKE(&=&4ct(K#P<$wGK_++LkP7lkD9` zKM4vfAAxI`O`&o7H*i{mNLd{$&V3OaW|+0~twqEJ+Q`yXBtM*cO2>jV(hwqhxDcR^ zjAc=yT&I&NR7$x9t9TtVsZC{$tD+6zEGn2Ch&&7)rr;DznK&`=OW8p~4Ke#yirt0R zhF7+QC(HiLiUTP(cW^_H5&~ikq@6^xu=<+!U=gMd=7dyaW-14FfAFy4Y=*`kt^BPUyKJkREJQla;q{~-5~GXF`{s>`hzVBWu6+}eRE zCV6cx(hypGm{{raH}yhYCpB)Olwm?J4q&r3VE=Zrp)%*HB8SYaA>0yRlY&T367uKo zsMO*lSsFadRT&asVgH%l5&icskK`tRV#WOjFtO}k<#hj^qc*8| zbLXZrGle6}rSVk6>?GDss#S(VijHlde>7)X^74`QX3BRca6Z#YER;PKkvb?#`~glj zr!}<0V*yT2*)Yr9!)ihftF)8EsPGd5lb23vuk1tqFGN~54NaSK3kEk>gd5}8ybZwQ zCb50> zgNbuRkF`j(0Q52G|(I$;Pzv0|Q?YR{f zCMJzJzls`sR3`*@tCO-qb83CRJhgheOg#}viHV8l?HbY+?S+ZwSMfipIX{Lb)Ar4x zar|Yo+D&MMtC1Ad<)*B|3Zt~=_~+bK(KPvw8<4bGm`EwhFG9Xfn>6a&wxr>dm>@S? z*g-BK5H_0HHgm!G4V2sn7^3J0G!7vy#1n&y?wy z_$8jlKs>h+F-kL6pWAU^q8MMIC-4E`9aguLhn@Ht^D_`v2pwDv;OeGU@swh?$larO zfN&Z7XT7Lf)NCD&*$dhf5+)^z;E$`%;mK0XZlZ&oeOh)d$M6z^((b|Mw)pU0(Fi$S z>7)<4TjeUF2}eKo9ThVsg*eYnB>LBWnUJ(W?hbxnFo+K^kWR{yhtk^=v0E5y#4D*u zG__qzT$6G`uJp6TfFq{5Wx%t!pq|nj^Hw3Dx>XFN!3MmEBr| za1jM*j)(cDT368&^-SSqev{oUwG~RaiwO^*ha5AmEWkR^NI44OV`9l9mR7_b3$ zzY-dG`&78s3hR`8E%8e!@B2c1&lWE(A1WsgUz0q1gL=u6JYq@m$XUrFS0@i&e{~Popk5!wKhtEnLJ{j4`BgZC>oRd6qUGm70$s?zVQox@9b z38Je;Y)BrlQZ#quI4Nf-U)tRmz3k@r2~wlPIUaONSutl%7(S8KV6W?Y_Q^f6URGhD zZ2fV`Bk8PF$s;kh=*Q#{--w@O9pwx7qq;Zu3PX>WChXfFaoYbI<@P0yoS8gwt=!w= z(yUg6K{qFky|I3->^_UcI2o}fdBk$js*yM^9A)Q7WqYP5Y51C(UoN|~6^jTlR)gXZVp#1?9u8nDjoO_nq&=C-rMtD<&@h)x2#N7l+Y!9Ve4+iP2GEZ zyXZ%P$B1tg=f1vuov?vT1VfjAbZhz|n*$Ja7UAFj!~wFGQCB1f;z@Ep$zw*uWg%QD z)hXpRuDJ2#q8szRzP^3Z&Dmdy5I$q_Z4tsfD=W1~++qzkHaA(Favd97;({_LWVPvM z!t(+-1TbnmhX8euww4{aSay>&;{T}$(s|WeSC6q;D%0T~g&FVDqVLeF%%)QHxPMfu z^BA&5UJ-Ddr#tI>snjJqq;1YlmH*qzNf~n4I}Pg*kfik4)jlX?vmO+QUR4bONt4mm zP}{k`!G7$oI`@xvIw-0lAK~kyMvaAWv;+E!^M320yEsZzpZY68_*A`mun8zopks`u zbN|FqiQ^Q}W?7y6t3+nb z!f|{*M3n^KL{3Qp7~~v4F*yg|e6r}MR%+ret7<*@_h<%7ZBgM z{?8=ymB?5!Qk(;Gvyd^CWY$Oiwyc0Sc9#z_#R;&HJb)@MAP$RZ3+LJfTS_3B%jC;- zQmqdIY$*ZRLp<75KH(P!<<|6zMJJJwh~rKNGCX=YAAp|>Fp(4zcTou^Sw;mMiIbJ! zOS|5a0P_7ov5XXv1Tc~WsNt**X(Z1YnXLZK{SxGNJYG{pme`?Va}37iqyUr*0NU`4 z7|~m#0K`{p)5uc-ltJL#nO!LpO! zO#1i;#+t|s#CvYH%J&>efq2>__p$7AT9+{?X9u`##FibPYgB_Wb7ouQz@6NE)oT>; zXmNJI#ckp|>o2uz?OsVrL(S3Gc;Eo>g+*=j{$)CDH}R;2=xp({5aNK8C*S_jF{H&r z$WSE*GLsVEJMR0JNqO_xepIIinl*2+f4BUN1qKp#<8h}k_gfB-?*p>%ybY3*a(Yx9 zi?#kF)(mF6pX?HMb42KDNlhXe1BcstM3CT1ps26s&O?!eN`*|}-%j-~3dL;}LJtxh ziHi~!Tir*gTG5ttvydNUh+sx>PVqK3l2MN(wHj&^<3S*t-=I?K~MS4nXMOZyledDu~UBI`+o8tAH?(30# zTJ>5`Mhi0F{9L@F&{xufG?EjUmo%Wz*W7AV0Am0eio+};N03B< zOOSy5!Fl{~zfs7%rDimm9G!-Sm)nfdy%N{MWUEl3bs=(3x#UT8Q_4ZsHYt)3Jd=GE zH;_W9~Cl$K^W&SWy;H``Z(vk zm}bUZ&>>SYr_|Vc2rc-ML;0iMUM;DOBC6!VP@$@94py~V;*DwCp0NnRlRala5Xq|* z4hARG0i1+5am|*sRVoCm@jbJpw=QKRb3TL`j(B~}6<*A-VXlb|YEfY7C@r3%aHd%@ z;_z_Bzlny1KoeJ0cDfZ|t|gxkXym;9`nTt$@hC*V5V+?bJ8QWskxXG|db}@VOTGk| zQ%l@MCOX9}oLI7i^&i<-p8h$v-d5OAU)JxK)k`mMANz?DC-zVvf~iyFAlB^5UYN>K zqp2g-CZXdxC1r@7V%8I!lllQ`%yhXeU6EbwvA&eJy8U*sUYR3(L-4!P-L1eaT5)uO ziVEbO1`JemQD!;H)exQ@BkWfYsgGxpiDZ3@`3;JA;>9nyBrM2VO$@bn48Ki<8(jnkN1F;OWHjfgr$!;%C$tiZs0~p~Li5cxgBOB#TfpGqLDYmV9Dt+sa2m@XOLc3w7=( z0g;%m`SN~BFh?0Q0h_eM;fX%VvPLwRMPYzD5&BI8s2@d|bnXyj zg-dCP7$N*ikPeXuOH5vS2<&T>h|w!RAl=>+2RqSWgTNhk_`qx4l^{BG3E3>9b~EcL z&&V_oens*ZG-ZnMF*1aGhZ0Tgi-##gbyaYPxBL zzv`;FB4nh;Oz3^YA$qbR)m4&kWSJxC^Q7657#`11>I4WE&2 z$NA^NGFl$Kkmuh4pd6m!4xeS1i}UnD1wFXm{tv3By}p?^{NfM2*1GOq+L48IA6(!zTqQVmw{v{5k)A z80o@x)r~LU?P*nOtOWrr=ldy<^l0vX@tHKRZs~BK!A>+m@Kdc*-0uJNu#c0-qU1A1m*4FC%HfaH8Jrc<5QF!y%VEUp)&r>o+Qu;}JmQ6@LVK9G`?4^X_`j@COVJOc9A1 z5uQn0&RK(m^V`PZkN8^Q0gY}{dQn zvCAqX+*i{;1&t`bKskDNcGj6XNA*vpWSM2eIq2M|8fYwzd1EXpQ0M%o{Qs)Hf{_p7 z;Z|c(YOG`OsKM#W=$)vP%zwwR7c(cJ8OGCwnVjW2%Hv3!+FEYI)*6P1hZ z^bemL-E$x-{IICMDqnf6B66{AC1P>LR>aeOxoD5diM}=nXWae6AJPy1i?6aX$kD3F z(D|pUhTplcN>tIg{ub|}n1xw@IS;&`A}$VWDxO+X95`4USX~@gRvb859QdSoYDID2 zfcN}JabSD#RK7Uyo;IcpjkgCDv(C?2EwrBEz~SPlmBoSH;we6FDGnS{$bj8e9N-E6 z0%4E-%0pTX6bIhbpAIYJu?#ovp6aGSg#KljNv#ObCuFTvvfdXe2acC0_Ag6ah5fOI zA#B;^vEpO*F@CM;TpUr$oa30D4GUlAoRYf$}au9DFo49<_*tb{sz%G;SwbFt6oAV zet-r8Rh&dwKQ0cO(q=Tk0CbhBmm%++TlUUT9YGr@`5yZnV$CU#J2I2q&Mra5BdOku-{g^c<;TS)aA&T!D zU2!UmIovV;EuMyW$2pjR> zIqZmjckA3fT}HQ)&<^WhEF(b=n*}$xi)#f>mFFSpNU5ULFOw1LSahb^|^=+(ng;u)f>p>QE|d)u@yCjE5V2HGth1LiqrDKn)9q zTifaB#HI^19(s)dz3& zBn)L)%RnKE3!<+T;R;8w!Z-(K!f(QUMcIrO_q&nz)cE#5p!eSKq$#LFPB_=fWV407 zLSJCz?oQ26tmn060u%kW#Afy?=WBgm^Jn^K;jR=BlI?gAeoCz;bbtIq>2yq z8i)u<6UCQ_$ypee)KE>Q(AU}u7y`~XALSEKa%lnz+Pk{=i64keqFW-KO}7vn8gEug zTj-^v-ZObVrFeXcS$AqXu=}We9MBau2hNvIk!tD%o>`4qR5E)Ierwq?p~=Z4>32x#-$8u93?U=Vdz31!yr9BbtOc_ z;Om#D)>yHK!TFn(O+r{9mSN>C1-5W6IZ#IH8|jvAZXv*?)F8!yZL2t>SPLlx};A+1Wjv7%Ecb9;Kp`Uf;nlfQyHZ&mwCW~K270#m$?7Wb)QK$QCY&EJ$A#lB6&UF(7qK(X)bV&8sO zf6DV`Z?Uh3KRb$jXZ6b_{cyOrOMcvMpYB>+?(jyjufN!LqPS~AvG0(8>Fc8vzn?1Z z>Zx-U=l_cxo5!E>m_M8N!#Fg^7yFj;<^5vc(c-Sv#l9_cox%f#_q7G)7d&L7{n5w^ zN=Io}?0bt(qmUuU9#&%ZE8=~oOBo}EJgfi(t3Gh6bH+d7KcVHvRmzZFMf@YaOCSBR z+{v$4W@?KnU)S*?Tpln?e9JHZUI~`~vPZGr6wo(q&CvadLy%Lu}JR&#lACW zp$zzKRL=QB{^Y+u(jOIf^(f)S7l}zIre#1B>SB3VX`g(D_u|J7S}}^Th%5qwzpu)LiZSGJj(FKA z)Y(8$HNI5LTD-etGni5CvrD zF8OACYS`tcL)b4=eq@xrqIa40F(CQuUYw>}}B$&eL-iaNM{)l9tBQIG^fncbX+Ux{W{+3AZWq3CdF7oTw1_(S;ep+1sz z1wS(VqMAHC#8c9$mQA=K?`B;A8c>qLLC^%YH~{{Hx!@3&5;DaYy)(W+%F(XuO=R00P+yCOBhf<#%bcxH$BMnMo{*g~?B zYDkuqkeZQtc29$x`{s;F_E>>A*WXtRE;Fo^Y*s&Ertsy?wf96DzfOD3ZBs2yYNNuS zC}&~X3q+8#j4)PBC(j4sH*R>?n}0s?t-@uQTj}SV$F*>a+f~?~a~nnm_v9!%J~H@8 zLcSbqcT;>h$epN#{V8|k^gd#}8%Iv>;*bALgzBuOtY>Cq@N+lWTsTgH272~(amnh) z=>t4Vxb=LeY_A_|4T!hhF~i@|Kb+H@?^Ct&A>B4|dRvz3%|`}LHh^?u=nD`~WvT?~tE;g}2h{gMpK7Dj8~C^WEH1l`TF6Cm5E0^Ure^!DaL zFNqT!^k0#3hc@zufB(zjk<*_vNaHO^^e5Dozi+y750*va;mmqniShGJ=wJu|y$v)f zd6+C5ge=>rCXo~*zkBFyi<*yJ^&_W0vb%csJTjxOGa+LQo+JycCaSNQ{eC~HR?H$` zA17-fg(jR{Cs#O(41Pg`dx!9NXrqw^mr_8wXrG8nRfZ7H&MFRlPs6qqL`4e+Q_V8g zC!)6gf&bXKNO+SJq&^WO3!jKypI)P)Sw}BRb9UtPyKJi{>V_ag9v3JJt*OG!F27z0 zj1AOFRi(}PhX7u00|`EN2L`sI(Cd?Sw-t4C9)E7Gb`DrjK)_573iI4*`a(ZJzx*fs*7%ZpMt_b{U%wa6>ue$C@S zG1M*M6|j-NUb|pgW1aKdi>PzL z&Yk6IMK4iP!6l->-FH7Zgpy6#oogXutTb#cu;6g=ALI{Ij$1~ZlZ6DHy_I}!5^GaA zH`AIsceXy~-+G$jCb`Y8(Cc=(nZn@EhFB)WWv$HcB#l8mS%z|vKsPfj2R2?Mcg3l_ zqi|3F_NEH^n&qyF&pXpCgGTut@|kBV2Vm`RRdRg#1Ti9`>qx({vN?=YQGQo zZ>KL-%0G8SpyYUUa^TiR4t{rxOGh|dgKw$0-cN#p_t$CRKe>~=REdHpC~+9 z$@4Ruhb79jD$YOs?1GL&dz!K)G)Y>{6nd#0kWM#o)F>7BC~r{W9@Qn_NSdnuq!4-? z;pU3;zr zt{J5k24=Av5qBopmE~}|K@h8R7k8$I&Q>ywvM&Ox(98KS^mn&*QQRW!Jp7Y+@$M8{ z=rVbdg?(+Dg<9ss+5&~?>zsT~exr|Gbw};ou+4qZ7-WdDmUIn2)61w<${>)6x2GGq za!SQ4br^(YVw2UjOa5j9?k&=Cuk%vnyVYo%ISWcS8mn^ERNF9ou{kvzG4oKj7cQ%N z?)7|Lv|awG;d?S1L~1VlF#gfgrCdv4km!K>7OJNVcqh>Ue=}#?ZS%98+_(vqek*sb zyTQ`}^>Z=j&U=CnM9HjX*$L?So94yaxx%Pyfu!Vz;NU#*^6-0_10hKxUdElIP)de` zWaCH%kE)F3w251 zlh!LUB;N@Fj$YVI+QR1Hqkd0hi2w@8ktP{N6L5r|nkcpcE`EMtGpP?-AYS0`jRdmw z{7N1QDKCcilKXOo{~x=sLLa!aJWFPc5t7LpI?RFE)ZtGA6WWqTL^g;B!jB+deU8$Z z(e_=Xa`Xy@tHMtyt%cw14@fE+Y(S+XNow=(@i1L#vaX zQXb2w@&?;gM$DuiUwF@C)u?Xwh!_zenEFyIkv|2&|7+p{hffRdNChKTQ1GebsL{$= zvRahij`HCiMAs3+faIo%3ptJ0Bp(^aAdlo%5h#hon%jlhsH$2%;Rn`RE}495wG;IG z!WOLL9bjnsq=(ODMS9e+ShD?0)7y@N44Ii@!O!_!)9^l_z^`)Rx)iUH!x}zH!W#Ao z-+aFC%Isq1->iQEG&=tG{I(14;Uh?e;{PN-?fV*CDT%JNT~*3 ze5K*|DRp`DAP@8kbg`ytvAOq91%gISE}4xatBGgQjIawUoS)1xS-c`fQDe!t3}jI9 zfZs@m^9d6&;J@E9*E#<=|G$MgsM2I9jzw$F5FJ2Uwno?34?BqOph_hjii1 z@|+_%ngM5}_-mFw&5ape;bbMIFMV~PAStd)RpTZO_o^o9#2KXC`SA_G`P`Y72xZ2% zUOoi4U%~l1AMpnFoQz*ofyT~@|8j+RjeQo8wFmNrZ+KMkq-JJ2jjT%2s&npnESilG zot#@AByUmlb5P`O3`R3^D`q9t~J>UQ3 z8|ROFx$OLz^Ix1lcK$Q7=Hp5J{E_pgzFc{}|NJ4BKPS(BPTTXJ^Wn_-gI_NDa?O`3 z&Y#p@zFb}fg-8BFiaKXOer5Dv#|5x^e&GBO8DdZeJq=X#KX)<-MPfAQrizu`-Fc~qwG5J8i=&wpO$ zp5Mf`Q|AYf<*DH#w0rD9m z_sdrn8+FP#q3alf=j(!`o%-@k0Q=Xii}PEf`RErpqE=0V0}33B<%#HmU+f3JTn+Ui zYJT{fj}{T7)$5~lppUz%xb8!(&YAqHAThu=gp^dH{Q|3|>YGr>zu`91&5B5iArd8pRsPn`b< z#3AmO$Px#HAtT6xXqi|U1d3}ECy6D{?F<&qW23_=y-zVfv=h$pvuFcPu_ZAzIHbV& z0pJYsS;;uBV4G*~FlX;KvXX(U6j=xLsLD>L@RVP1exn~S#E3_O(HkHZ=D`t=7cL%$ z!OCv~**YLNV#K1Y)f0)0!7b~`MptK9I-mapc76(1)HH>^%rM}9HuLuIEtpa{1CEIu zcl{)Yhu=X}agQ+Vy}{;#2x;Z{PfP0LXCWMA9uQrN(BW|P@g|G!s)aYZSUN-dQBsvU z2%A@lSvYksoPPryWkNEz>IB4$B|g-;OrJ>AqJmRqz*>Wu`r$=3_NZ zX18zU`g}J2h2k!F32^vr6e7GICHw9nHRkTJEA^mgPD6pX1Ipn>T7fk%SyN!q0#2QB>p*aooeJ0 zy>$Fu=D)y#Qziw!>?<9;xa?!_=d(KJz9++|9gF*9`H#iONCucXLS5_yCfxI1@D_Id z6Tj&>w@u~&^RzlvS-lybshaeKU7$ISnad|ky-Ny#lY5lYTIg(IQ^}MwOaGc!ZjUI{ zYL%jkS{jtf^@(g#yfaNP&MBO4rMeR>E_aSs_qDLIrtEfOM>^3+C11udV^U9eZGNrp zSNjnPDb_kQ<5l96a+YT6o>VnCrzE&U${E|Dt)N2e(mbg}$u;a*F8h{Bh*Ihh^nyiO z)7(O!1yQx8Bn3R#0iEPCqVkwj%x-9oCD|wcjUp?R5)CJO-h=1WX}e zSi{v3B-RPLa!bvrC8b}vpu!ycf3LvprPY7+?g>$f3L?h6DhgI0!&~cNxA&7lz1Gf#mzZhXSv5B zm(2R=zMA9Au(Ge7wQ`*KM*a<-%|!BoYNk}KE_;}=VOl#tC(FW*uXuO&`tLjaS3eBka}ldVl)!CBV`l zneIr)6DBM!Hw=vGJ zs6O5xc=7*60%nG`wWo**SeWz<*$G`3+U9nPg-CsAl4gfiO`%4(o9iZ$0P4Jumfln|MQg!2m%uA>%d(Wo@WFlD&?4hyCFM{>~ZZ^V!^baOojbBMKTkEzDgYL?ofn;BY#Z5m6$ z2}!6+H~P3}DKSYtArtl#YO9U82Dt{QE!0$R8D|C$TE#WjOe=-zIrA1)U@ao9ZLcLc z8P8TtAFI;4%R_{^i9h~jEW_5eOk#_acgC-IUQ{HG^*r$4qK>8I_!rfKc!+j8<8Gaw zU5c9w8n<)pb&H9FYRa{!Uvwti;s0u7WTq@Cv0GXa-t5v%IfZzq#3p6Zjrb?NcoRSZ zsruhnD4FqmWp|XIKF#W1!u?vQxj}Rnkx@Qq(ZKGzZ^7teI{)LpR1R5=*NUfz`D703 zj1O&axnE4GM|3h#`pq2$rtShaHRZCjrUrz}N38Z*ThauY3EgdJ>CO8~eMbra@^eS5 zyAuwzHc*G*?tA99VVpx7sw2Zd_R7%6-UfCJ`sUV z9(Uh8FD8{sB9WLkF9ZqXB5`fJdvuri;~Q}btV=cW#+Z%E%pt*y=9-dRo%8yizaM~1 z5{aP=L}$X)p$)lItTmNL0{=I^eTC6lU^kAxlZA*#K+9k7sFPYg;A48!xpTUSq7>2_ zJ94b9k;+Xs&*N>OwS|@`+syg>)5z1PVhXB#ENn}2X&LZ6{wG2ON%rkb)rih`cdU~b zLa$YY2SsOW#2_%ec?0Dlep5T*pl_Vth6_K7DnVW>8FQW<4Y!j0Md5bmo%0k_s34tR z{o4N8ZlW$>jEFPQUEjfbYbYPRr`&o%2pt_{+GcUa^%*glPjotw2wS4H`7MeYbxyXk zQd3F{@;DeU7&Xb31PKSkR4Rv10RD>GXlze(NCaqvVY1>&bazUL6fww6pe0yxF;zE!R?+>F; zI{4eci22GmQTwtDv*BR`t4>3Hv9rLBe{2QLmdiBWvvmnT>@drRCiySXsvlf_GA~sU zp6QbTwoA7*UXpkyoz3 zia1&asVrja+_^mMBDh!J#FB~jSku&8Qz}Mdp}kRjO}d?%Ph^8co@8?@&)CyqlVvPC zh)<2DWFR)zlm|6%7#J2w*%fIS92YCAZP=z;+{U$m!FsOlg8`27PHmhr;>zyoE%YH*J2B!dEFpYS5B zN=-JA$|cjH+unYR6(}2G@-UHQ9pICGJDugV7zIOzxe3&4bBVKgHZgT+j1_>woo2Vc zX3Yv{Cx*e@lQFq&QlO_|p5O)6Tr_lHxP}tSu^<45m)&?0O$H44u#|tp6jeIRCi)vs zkU|Z12+DJ@>X{uK?77iaZlOtcB%SHg10w}c_FH^Sbnm~v1h+;zXZGw;Gi)joo0>^9 z$(EqnP?cyXjwQwyE`Zx^Gty1L0kKaD$$8=lp|aUnbSu|QiBvOPnpsejJ#1R6Uzp=% z8O@i}31P2#m)d+4_+~V&lFVgtJft13@Iy}H~I_RVv0(R8IV zx${n8WrPotog?cd$Le(|J#S5JJp8Z+el#z@&3Z->m5%?4{7AqbComKbdFx>fuTbKcytZitrIIq%U$D%z1XI|K92NYB=hHHSymZ{UZKp8X^1 z4vehZ;EwdH8(DYI9a;CmNYD0>weRuiz(`O3$cCPgo(&`Gdq&o+lMfp{c7ED0vTpC_ z5J%Q-a!1zg5*TZN1oW*k^4g6fYx)7+Khm?8-;DN+tli1rBRz*ldT9EAjB?9e{vi~Y zAPS5RfWfi$|7?h(XU{VI*&_h3+XWgpuiXX;JNcFI7!x8G3MTx&54mUpBpR=dOWcVQ7VN&+hHPIwo8|_@R%W?f6XT&YY&dBd(%~f zHjS+L79c=U}7+ zt{o3|43pRGRgFPNe8^u3n!<_?oTu{3EgH9T4uz9ogEdO7A*q@>pQHSIFJ1md5r-Q7J*u-Ep1h!dDk;1 z$i;SgmXEC2g*k~8Vd6TVm^ZYQ{FOK64G#*BM4NDT$6$#e8#M-kNNtrGLccS$>HFk? z=cmHhaK~d~V`u=orRu#f*+>;aZg2!|BYwwfzYj!(?%}0wTGeBQa4r^LHxawnQ3M{O20;9H#A!nDN??bvq12TfH^H zCfIMB=-PKj)`+tdg}8U-*bGOMqXsDFnu#TUT^>ih)tY|izx$CfBj?(2Wlh%Q1bW)b zVYRY^_u^Jc`o!C~w?4;m%xt`oi0ogq$mW{1&L$eUK$A6miY;@B`?A;Iws4Xe-iQ17i*-o3A3NTdU^8lVuAZF?l9}T~GC(Bjd?F}vNltCqJZ+CrtQ%T57>9W8hT*=IwzAe9W@m$D(GQ;7*293%v?jPk5Ea!3c~rI$iRF}&tvESw8dTxElmPb0e? zkep6s2n0fqY`1-1Ky9F~0Xl8kH1>(i(8Qo{K%{~TVu9pRO-Umj-Vu2}Y(|6VMs;PF zLA_x4vPk77#kCuqCrw&A#krBv(pXEPUIfCnN=KMfAhpce>C+d++C<`X&=+r2KBG@Y z?xGr|3AMVz;K`-PFT~}&Qr-)n*L@|fhYd%nY&Zsbh&&~Bsthlr0RbuH-&K)$twlpY zPx+*hEweYkL;cM#^4e>kgGH@!fSgMb%{EuxjhjpQmyGkKOXaF|Y9NHu-D%1w`Ajeb z+kmDuCK}n5!=|V@(Tt6GqE_`N+nx@!^FpZ^&VB1$eM zR(;@9Mbz5(J~sZJrB*y~e1`YJA7`@G{=dBC?aM271pKRedDD^0AFOmQZ&~&AhQpUX zIR4Grfp0b)zr5*;`^~0(U$5)=dL36O)M-51*YOpK(D>L&DU?29*ZTrP`$ij z+2s$m23$VmeSK=><+XiZ?}C7>D=&Zese5_(r|7=hj)B^ zc*o@r-)4+|99{2z{pkQ88RGJmPu;KIT6uYUUbyr1;q6dzdEJhG3>@amdtZOJ!NdO+ zf0&_L8sCoU{A8hjMk@U*=y`Z;Wt^{jKcH{l<(-=>^F?Zq`0zgt=O1w|f4K4Mx3>A@ zarMpmyAdaRxqS2>y9uEqDcDn6ouB^sn;pl$UZ20bbLBVN-V>IFHfKEBL!`AC(S6v% zAJK;(N>-v}6#xQs(S%|8Z<3pWuzCfQvx*Pe#1ldmL$t z=&b6MrHl@Ly=$P<6K!9)^P3ePNZXYIu#eb~iI=y2DuUg0-0S{9-ga;vToB5tvJ8Ww z69r{+>GGzX-@Lc}>)oGTK7$S&zr1Se@Q;mc#!zdRTz$>=WCuX1Ve( zsw=+;)t)t!xc}pEU$5-LbT4mT|IIQ~ek%lTbsm@>I*KA5X78ip9jRnyz$vLJIU$*^ zdw2ZfBzA>kF(dSCR6@0nD4due;@I5dv&=}DA@@(tcyjyEO(o#!WY+I>?wc7(w2ruG zz2^f&LSpPYcSIn-C3zdIk(JoJqlV3>lfjXcHBwxyuw(n%VUEwXbHU(pFABWs^3mgh zW7z|Rd7B$=3nh+sF24hJ9tzYd4SJnw!PhqITPKGO8T8aYecf}mKJe~k1pPrEy%~tv|#^HBIj?=fscthc1 zV(DWI04jl@Zy8GP9F~Z~JEnQVNjv`tQv0RH3{k=^m&&#BQj}wb$HF+*DrebxqL>K8 zT}^Qt1bY((%X&e|n@P~P)+JxHgI>TfD2yI~AO-N0aD^(ywUX-#Oymw`Y%#5f0 zZTrv)4YO*?>zr9FPQube=IUMur`{5H$cd%~4AwQ-C2OdT4W|>eD(F-s2Wh z1FeAzNkkf?B?t$cN%zdJXXI2oa`@TLS4v~a(25Q~gb!pn)S76|5Zo@~v~!4Wf@kWS z+2$f#pJ=}YFg^Sf*4=aOvy1^Y4bj}2_N<5l-t$gs7)NM-&ecL>5CL*AG}KD4JAowX z+-a?Z+zT(ca7Obv>YVGY6EK8g5Y5F~)USR$zpQ!^*yU+C%8490;(A)8vTWsyF(8Nq zFU>^yrcX>5nU*m?D5qf&@@geaGn(Rd(m;N0U@?j%gfqR)x$&l%9cfWb7*2rAC-Imw zZAJu+K})nFMFDm>CRM<`v4a#5eVsgHHXW8KoB zY|lZ%u=>idYRH^w$J;RxWu&P>XmkP;C9OwIj9?o=HiuS38#MtqVWxcTbtR{Sy*a<1 zR%u$5Hf{W6Ewgs-^@9v$i1Wg{%5lbGbtNYUAE8`PQD$-y`Ow0OXAz3&+;+Q|XfwBK z2@z#i;9Px;6*|wI+b5L2OjV8d%0)VlKK=LnTVJicbnw#tOM5PTs$R>zwCk&tU#)R@ zbnwz4emvlQwURF+DX>w_gV8&>B7?1u3^}*V&)?M0Dr$1gga_Lik>@{D2a;aaMxbR{X zDD*&!fpTdtP51EdQz3RGkox(RhNt)nGtEH9fOYE9p-cOiLhn~PL2?DmibB-+*&H8# zPtm%Htq@}PJ_;zdFejUq;9}Vac8q-T(h*QtZs)A2f|oR@Bq5ZO&Wu(cf?)~(XAZ%N zC<-sFcfab<@%DeURy1vo=*E6}EE5?nlZUHe+kQSWD?Q)!gAaGI1(wHnkWhW3?AQZPz>npj zLK`~I<(CO8@kOTbrB5y$P-L<8{jmR2go6PK0}fsK%viH^jmA96YJlAfs6$mw1JG3> zrLjC+`PH&I=Vsg$u$N(d5o0=2o)dZ$Q$$GT<9Ljf;;oDx@Z=N*EcUX`@-~#$;a8y|I&pa(DzuZ;A~C|UWx^6cSO#`IRmL_&nZ=vEVGSp!Hn5Bi{roBuz^PC# zNdupU{O4<633Q`G2b{-W64b{u&(PlbA=^1pRjd#828n3rOizw7_NCe`&d0<`)V{*C z1*aWn^5aHGN`olc$KpFnoQOb@=_2WzKcu`6*1Lok>4uxQHK_=IDQn zUr`REzRJ#_&hMTvYo5YBmgc;Hl83|cnv}S>%PkTu>6~Vrw?5<#^0O29zwVS|@jB-< zb2kLtmZVdx>$xeDO?dYBxl2^CJ^z{`bU2;kP4%G|VQZw_@e3oA2B--=za{^EHHt3f zqT5?@Jp{Wcc%Y1D2zV{nkgKk0g@IPGzS#af+n*Cf`J3G$1>k#H8iY>>Yq=71e{ z_wECU2-@nLM<1P+<}A+(6-{I^aG95yATKA&;FC!~nUf+j0urOpT+$MWCIND!mqlSR z1@Q*iOgg>{RoDma@T^mE9k{MwA5Yqwd4a)uHT}SY>6@>V^8WqPFQWl|-EHLFR#MW1 zPx=a~fwqlN)Nu>$^hgK<&j!sTQdqa$URcx69M{);^SUSRu_W{6-^{BG*I!^G~hdOrx+;AFVc|lCHMrpNXVK<0fMyd3zx0#nR;F=e5V^7YjuSJS& zjCLMHTumP`7X4EjCy|GW0=NUj>z52!5D(5Blcbyp6L?|63CL?UwxVn`JfJ%MT(0*; zl|8o@@PdxMU#cI7G!@cVgJ^z>$erHBc!a zMARAV4BU+m#+AFVoZxK0v2wd%h5;NWrkhgW&MSX>MLe_QCv+PJi7#~Eks;Q zCq5VGTz&NnQ8M)bKmUcAmE=*9t;bd_RoQd&i&f;H`Cp%@`eII_Q}LnIdXYu40YTA; z+aU<=mwC?vgBqEDnubJ6@P-QV1t(0igGu3e{|HX^f2u&s+)^Q-^_>YRW$)XpBk8L( zN91`@@_0=q5~+G7U6RT(q~Pb;ar~vMtkno!(j~!`VI^5I-I7YTdHMM94$}K3-7RU8 zxuMmPQU-LXo$nvhdFuDp9Yu0L()9!YV^kr_5`^q0^t%1(A{pz|A!A= z@`crdONM>baF#cukLFN5nIJ{Lnn0o#1GIU2zfk^)Dd`d>+HVV6CqzKcnllfT_oYUP zqL2xeO;ZMfy>c#)kZk)nH@dWtYCpd*X7eV=C1I1EKY^T0M{9G^jlTZ9A6f@6A1e~I%g9M=6P2!$~65fQ}`f>|)T&Xyq zx-2P?D&eYh)S7&~Rqm;<*_2>KK4ps}RM!2BTL{u*=(E91dZbX59$L+AbD0T21F3Tw zlWHLyF#@r2EW5D>N?Z7d^ORfdR`k%5y-|zC4$a(*vRji&nMPMg%ayRYP#HVdTxph%JQa= ze8qUwG7cG!+WW!r#@{>qb^y<IPlxm0o%oDKa_CtPdX>s=7SIH|-wAT_uLq#nNu>$p&W3gz!h5oo#}h67yeplmhh z+7jc(L^$*v_R%4^i;i-Y#)rd$1HYb<{m_hWnkT zVkPO&5Y$#e=jWhk;>IsrU)knf}Fg#gVUOhs9o#Xxi3UWtb!({+Q=D-4=CtdK{ zDtC8;)Y)bqd9GQg{Ci?>7*#k8ca~p}gXyV0Udi<Sgtiv7+RM)Q&Lhagmi@Yt`Sd;r}n9YQ_x-^(WDLPd`QV zqri$)nr_w+$dx&G1#y7NMle(~&20fP8cxBC1GcbH%!#u3H{Lb;uJW!&z8ig_g1`8d z6T<_}&lZe{0oATKN}Xi~J1}BYLuYP&gVe&uWuXO@GCYop9~4;&zR)Vy7a%hI1NG?8 zg>4=WJ^N6BhU*rpvQ?xx7FC&0r%EkeHZY8!;W=ORBVWKgaCRP<+YJ96I<1E9V7%_ zPE5+rB9NoME>^1gIJZn5{t$f-0jV9R6M!q|U;l-bXc`Ly=bCYT#T9emN*1|&LFO~7 z&i1KMP%fmx&ES$+MVT*-A7mY(l+T28851IH)aqf)#NC<35bg|Jva95TG3HDi< z;?jZ*xCg4ivl%TT#Is2%V8#`I^Yn}{wQGxaXV{4EHpgC7%(?CMp~Hj@C3%CW&$Uu9 zDD@kABJKs_>G^=6(nEuSp_D!pzD;pUjPus-sa!W~RA7dK;b;;D-zK*^R?F+9S1KXv zD>)44W^?U30KVs*a8!h|kOWb)U!0DBI@qy8a?K=_v@@RDkZ6txO>OZ`LWS7j8~RB0 zj6Df2iFG8=IMo!>Cu2orcqd9X;)u6ZRjI+HZRQl;LMsm7A$?h z{T3ZC1Gc98XqHKIo9$ThU#Vodq)1S+A=l={3VSfbp(7nqd{#QZjvU(0cFX9@ziHfj zKNQRvJ9K{jb3Z<1wKm4sBwKbwTqaU&@h;gPCBzbw%>0YdNL2(CMmNWG9kC_q&t%V6 zObDGZy~0PpK_%Ei>w+k^G1rw759huX@D7DD9k>JI8JY?wItpjbeT1vxmW12GVLDe` zUG`;9JrmwYT$AVUM)3ys2BM0~-0_2;G+>2&mY_qwIFhua8HVE$ZS_%ZuZ(+2RMole z`b8%46N7}61bvmoOwm3w>_hxm)*&|m$3%#<{%ssK`f8D8f8hhK!=XQah zY$Dogkk4&ntC5piX5~)m4raqHZsoq?7eJ|}6> zzu5{#MME^F&iU<(1?RSzYl|6)Oh&_<$_tOn;Mi<7mmQb8NiA1e@nb573<$R4*U zN*7YBFP|@QKs4AVj+)ws+#oJaSy_fJi(gGy%J!u@l<=Y0hGFS~uMGtJu<(%ujZI0RWZMEleLz%V1~g(_ zvkP2u)miw&I34GWsgVGFEwQC>KN1hnm6JU7$&+WtWI+Xi5UZ&uRj4@6%{Bz2UCBk^ zaJHHo%?1jG>a8`1lJTA;I6T%N$>)*d{n18YRq~$%_FB-nBS9D=>@w$)P|eK^DGC(I z=|y25FogUvw|F6mSKmBE)I818}yhnK#gA9>EG@r*$h=S(){`Vd-8JLi6NN}fm2Zxv{Ek2LN87IFvzgf)( zY1LChKs2D1tfr7M(LvM$>Iu^&+Qo~ElA%!LfaXM+eknFe;%pFW$?i=e8XRLeM~F~_ z$vQ#4`xAq)6FxCFM%bjxXD6`v0m`>5jAXde)&t)E%vLLxgbJg0h^i< z>5dc?vQw1jq~@-MQ3l4A`(U&i?z|g!&RfY&w2jqRV_IIAEUq=U6=;+_o^gKlq~a+92RLAG zVI(rm0&}s~lhF8^Us6`fLI6<-90F`?EL_BJ^Xwsh)o`F1I?NR1Nqa|}ok4h!A)hXr zOM55qOkpq1jUeDkA=-Is!GafwAvKpFm8LBOFC1b4CG!@+J_J8Y#n*uUS=bP7Voye* z^IEgGtx}2DTW+ycVHJp`P^PK;{W5{mrYx)~o=C5xxGFL8xI#_J{GaoDp~uW)tZcaV z!p>wV3HU~lWg?TDGo8D*!9uFjuyYW~WeyP~tWWfa;n>-U6S5PDpHLXItSA+^^G*xZ zznb$XaGrnO8#6~}1&o#GU5QtRcVep5QefJOV)CuG!es3$lIlq0G9>$^ow_<%aT5_v zNR3QdJk23EnLomCl1s+(s!;GsrznIS){w+WYp;d9C`7wfdj+tkpaIP&8Et|jXvv<; z);8IzuJYUp`#}-vt-55z5XJsUlRP+~G&nEo_O(I^8h^Cy_#G2Fze{4wPpC{lAEYv~ zH?VcR;TYmVrV&|Xm}XvZ($0^5B!X;A$dCHLCoD=AhY7=Z{C9uPe<+OldwvJ%OW81~ zfK5y-kNqB7entRtI}np}Dwbn6qASDc&1_%)dLn1rx#EpWXU-*LGkw2TPti&@r^7B}dO#quY{e z%eeLD4rI?ALmF8)h*PJUa;&wUDP+>*q0jhO7mYzI<2*UtM+KSUzyPfl>KhQUb%^e~ zh**ws zUmU==O78V4zHl7Q9V@Y1$m4>0#pMPR2}6X<)U;F6~37e zPzFhg?xR9HjXBReSD~`jjOZw8!(xdn2eZfM)@-xIPr<&-&=bFq`qh^k4 z%%$-tC}~F*v@!i(fBhmbmCZ9sm9ZwAK6_L=JyRYH(Mgjd4GskCc+bswK?fEJ3^fT& z!Vr2=RRXEa_gilz7Btq`MWA;HS~lT4^3!?TwUHo_Iu>n!V1z_;qGO-sjr=# z$v=+KrHCJaM%0ZCE$0qo7|W+oRi34Z%|+JRM5Q+lZDGPwFM=T|&Yj_z0{KUjty%|$%ROMk98G6f@}yZfAi&kuV@svCChf4Bw{ zO4E$ArC8uJsTkMMg{E4^lH=yY1*&PBv`w_1bQ?vjsWZfg> z9IEgM`lau|Y^SsbUR>(D#KBDASZRYxUc9da#Dodc>{z7M1;9J`xAN}>@REc-YR-5m zNv^(idJ9Ce?I|$c$%lm)Au}qvwA8oOYtj*bb z#U_7!pYTl`Pd44{8CWFw&(54CYrCoqLY27LA_V2YN_r-X_*Q~jxP?{r2BouHtE3BT zDD`#*9{a`19Lb~HvPUS=HX<>)&rVgCkfl6NVU2yED)j0b6?VfI@xQ6^$s3jIqN*Or zW2xEV#-gB^-3d9LWOE|!{PKxvl>8PMiPc?q$y*ZJ5usS~9;rWr1_3{i%8hTV%NbRf zgXNUBUa^x<_T4ZmCOp;MB05vxbAk8HgarYI97oyf6F(4+1yjzO`FGT^8{?Ak2(Q9h z1~rruV6&?yHr=WNh=vA59&X!}n|k4fef{+TkK)WQ#fGa4Sv({=Cm9j6=PB9Kh#-PE zH&*#7y-4Nuw$`uIvW(HPRSw4mF%htaIC)bzREx4<%wlv2&oM)e(_Hg$jy63~YIg{N`8_XZ|dSN|6~g%>g#18LNE;#vv3@3 zoHG^nb#UABxs85foto)Rw>Gh9$<7^2lI8azIT5U{mwIJQutdPqlY>6MllX@%$jwyk z4eUg+y+=+c&sxZ6>;^QJf^(fLid_LYEd{iha2SelV$R}NC{?auY%+;tEt3+-DV(3U zh0PF1HEZ&gTf5@yQ3ke)sz#%tmGi(OK4)6hB8bl|x0UfpLa%Bw;sl@q=%A=a%ns?3P{T9bt{ty5gyh#)S>Wj!2^bxH0OZ1WaaEqMOIF&NyK`eBDd z{H-yB-VPtmZDhc?uT0~;y@@F%n{}6Pe3Mj_LZh-sBI(8ntq^NK2~g|q!if}T>U3^F zJ-M(EnX~K5mGdq^AQ{>#h%^$qXLjePBy0rKqEj5vrl0bR;dfe8o^S2Be0S}=~mNy#>V@?^*7EIO+MDmdJ1XP z$DH3zzapf4MlK%5VtlXPeO7Di-}CR9!T#{tY{o=2f>PlTTez%`>p2dGpV?%*89 z5%Lg^Q7MxNcPvaK;~hpIK|s#Wem*BdrTTbQge7E;qS}<0Xa4QWA1f;?M^h5}f$u2v z3X{{V5+7Vkz^takz4!!BG89tMtpyJR_X z8V*eDhHD@~R#T8u;hxbTM5=lPmyyOl^i#sjZGX(vwcL}kV?2@y5SwR@TO;wTn5J@(}WYN`1d$;ow=}1a$}B@z4(@&59`Ll2Vbrm z`BPtz$gqxdm0t3D-ZH!elV!qRSlUlo7b!x*>61QwuLcJa8HUf)Ne06^d_H~Q%?msg zUOCS+e-~aJ^+S^c4-zyOI*c>C$^Ilbx^N|olllhl-2TAuR+Z^la25R+)J!guI>b1K zZRGwnw+?@z?GBd}2D<9=yUClnVwQU;DrBp{q~!ocX3<0$ackZq+UH?F)(N;EDxpwv zQDDenNjjBWr$AbYWM=-iim7J&L6RUYSZfYx6{~9t@#lXUK1g5E7bRs)GMFSsndDaC zmYRxWgK4^s8Zf$ZcKDQvlT0-<{T-MXn!iXhA})Tasb!KZ>2*?ff!xO9pP zrWMr=L&R>9l_YOb@;OBlkYm7lYN>|v#A{(gVW_^@Ds&LZlsjG;$T~+7+RSJ;xjN_C z+emoo!6=RhLrXt=SMma0SG`K4IXibgT8)CWeDFUS@QTjt{3?@X1q-cX#59g#ID)^X z9vXwG6qq-gNdBEkf<$fPgC%_w6{!$E@uA}bSeLLl?EGYw>XJ$H6Q?Q(<%dP+zTx1s z>-SmUekPcP$TF%Yf7##Who2!}lBx`LfB`Y(s=x8vSCt0}w=`xwnKU3>$pWs#|vnGRr9U!#P%cju+&3 zH>Ya3=2ot_W>+zp%dl}SfdQ>c<5T@hI=SQ7LSXBFfc!)^|Nko|=v;jpYv-z?Mm{Ei zkZmSB#=_=QVl1G?kDqRE0k6QQdaqX{;#{yx+(x`B-MCZ&P372wx^PgHa6#JdyVJ>~ z@)HN5T&fexHnYznK?59S5kp1HWbSXx>fXAY@Vi-e9y z9RBi`AP!bcQbWxzC}E7HAvh#&gd*T(Q44Ml5{@Ku1QI969OWr{CXGM90NG}a|HwT> zckD32%W28x*i!BuK-v<;o=L!mSXaUzhjbb_f$8FLS)fVwk@M=Sr8XEhs==uP|F#M1K-ud%IQ21mbV2H(DD(w`w>nLATYeJT0=C=l)Thg1QzM{nrFLq()#tpTG%d!~o8< z*Ul-sS8n|qlfhKE&V=8$FsHaBCs}4gz~70ijFS(#=qs>&pU1Q=d}*vp9bgo(7-Y;g zjY0S;a+is582GMv0d=8jTkwG>k|mO&crS7-Noyj`PBeIx!OmT@yZW&q@ z%eKUFczR61YZrL+CxKvgEhriQHC9j@C!`uX(uqb_O679uV#Xd?cCME@B%S<${E1p) zF-$7np5Rc8a$hk5uO!fme<70pcML6~D4Ty@f)hvPrgkDK+7c43B}b4Xj1iK-IbWv> zq<9N47i1a(Arm|IM!b#iFM>9P4m5TT9jGV9tMwco`J2I7QZOh%b_$p$x-(hEYaCjZ z9a<(OvF@EbhZDo0cUw4f@K2Xz400LD&DEmL$4N#}SdrA!Rh(t{hH<^lhNqNkOT^nd z$oW2?1Eg4!SV3n@=rPrB<4uGjMdLkZUM;-gKr1QKLkFxznY@{ycWWR&e^D)fUbvPd zl)&V%gLMO`%|V_(p<&3(c|`b#=niBhej>?HxWs$KumxDxF?65-)KN3?w1$>(tILa4 z0}|bxL+=XfL}fV^S1Ju*{D2!XmV?BbFo$aG=UeAM`aHl-^6Lo53ALI4WYq#)rF|gcKYs`PnRa ziM0sw`Jk~#`hkbS2Sq(gLmI2AZ>}}0nLkG5qeKCE{#*1W=@PM2F%lO&JXzT)Vos>W z@`jtIWwCP3lS@vG+O(dkvTnT1`)riTDmpPLGgB_H>{yvpacLs`MWSdpn+VKz$&Nx_ zXU1JpIAJ0KN;x!~OH$dF;6I`w+KAOOA3cCFQ&s_!f)Ov<5o3X2ocyZ%hFRVit{oIy zq#RF&yM%u{>($+gso9o7A2nF{EyL)FMWL?)ZEfZ7y)Q*>1~0dYbc*L%&XH2@?h6t` zB;n4vEMKQ$LkdXyNkSmDU_;<6C$-JEh6)41uOJ) zUVrf^Tp4lBYHyy-fm&Y&aW}$zfyNQp>_T4~2>SZ?#0(rW@6TcFB z2*GJ+me@EF@QAQT$$Fx&i(oo3jN%+6&Nr7te`kOcNM6DmNU{<@pL_mU&JlTkOi0;R z@rul305p7Wp}dUrq(rLeCvU#^PRp?2q_S;T}0lR`l`bLPziIf)wq z8naO&@eVK&6BNudg%eWjgwQbA-bpDOBZ5d4Pn;<7YDzRvm`9XYX!rV4E_;3wi=w26 zi4)_5ywQ)CPdnQ?t4uhQf`C#IFVN`Ii;_B&OjWoq?5$y|-f?GzZ@>?h+>KXlyHeA` zeOD;jDZ&r$zNZ8+f(fPo6)X2|W1^Mn;dfrF*CWs>x$#)Wx#^a|=Js~X&S&OaflU~g zssrI(-bbGxorj;|-Vt?Y7vH_O>Ehmt``n8k^Km<0K5{SaxcK(PKK|WyanHrw{QF+O zdDl5VpIhoqQ84z?zg}I_4dX6?#1^;fv4Aw`4I5WNY3K?yNq^mhk3=l zxDzxL-+c_b7kq*L_Qfq1-<3a`1Q#A%+$(4VZ)D}c+x)sy8g0J#As<0+JEQKebDtF~ja4 zzuuOC^wE9=v`v^;3l#M!AM}kY7)1?w%OtSd58gu5dqNbjx52$_cItUZ04ZU$$8?_j zBQ3+w-(hf%z+j5twgryuWmxFkcyTN3`;3Yqor~|YxcL4+zpWzLs)85LbuU5x7Esve zjVMA^sVm3#@Y&+^A$p)hh-SQpI&7pPdf@9VDz=xfr3wCr3TF#Yfn_f5l282aL!*^J z8&ZwhqQ7sH->vS5Y(!TL1_0Y1)E>-jp-4*9ev=rgfDoEMa3_s7@vqXcU1bYjMeJK> zLW3RAP_Ma#-`=6C>Ki77AvjOGZj@roMEJbM#~xM@`oK;s`4MlGMuqN;QRq3pYEWz4 zi`puG45HcvixuW=SGs%U=eLD@0bz^rT5;DB=XK+QfOe`Pz(MD}UkR!k8D88Ud{j3l z&QcMIM4SVY{6@MOb3qS)(R;DinqLHG)KZLd!cIh}qLJ0gX^bYqTWy2jy~cZ2d#iDz z=LqMm%M5Cm^G{bnm3aS;#^$PQ{uXMXmABcTK55 zvnw|0??@R^&)xeR6=!Z}$Tn5BUgx&^1Y+sC=WuWY8?47W7c z-IW|W&4G!O(>OBqGR;dlr1-6= zrcQFj-l)K(nd=+aQ)o-Ku(6P%MiU2va!G@4slkB;m&>MkIqFVGQ4W?i2@Wyjg(4&2 z&EVJA%z2u-lrdXLiDSk zLF6!nkvQH7?a6!9O>^4f>9%?~7PO@bCQe)+Wg0^}IIoz@=*ppZLyG7j(UM^tiF1nM zW)dopB)jGR@joiFzbC+w0@}r!o}5o`Do3m+L;T?n(~|6kb2J9$yVCVBc6?DF5RaiK za?~U^B@;_xJW3?lsVR%Ap*hx+L+TblHoZi$XyuK|gE<{(w$W%?`EZAOG0;Bj?wq0!yV$H0uQ?#<4{j_M}Ok zR|_S^nP)D4u7o`XLuQi|U#7lSl+e01sS*}Oj_Yqu=H@Jv97D2<69+)z%^XnT){;SAFN7*)b+i+gt({cDLe^ zA9gG)ej`^aKK)GP#fY}d8rwfqWRb+y(e759HX|AYYXCWN_Ac9#ZO%;CEuT2{Tg#U# zl7eV%RpTgQlPw`u<7&kSE}KllvE8g#t$w9^LlWY+`7PwmQ18}zX!5O;oL9YjzrOW7 zs?|)gYFWeH$Do0u-LCk+XtygW7M$2Dw3iC%<%*qUhxS;TDs6FaQ}Ohg;^4vJ;Of8U z*A)ks6$g(N2e--R(<_RD2lUt8;$VN^Cux7AIQYIc%NGaV<3IgOcl%RdrOY04{*Vr+ zgY*;!59^2bi>EgfPxt8O{fw+17!4E*JWyB*3iAB)N*Tv|9t6T^i>9Ew2OwVeE#|ZL zYiX=2M)@}G!iFOu{Q|T(`45+UI%Z~i6!t4gJBouR6kTDyE9@RTQye_0jm&2_u|dBI ztMtRJ;^1-p0NtLb2A3QxHx#qHWtaN3Jh-dBn2A> zEFL2HZFOJ^0!ECWWPaS{31JgRS{aIlm4pnz45IQJ{7`jBa0D{nGhB(FYbAjfmZ_(3T9l|QEh)OjW&T50h5g4x4A&hMN z@{iOGKmNQbAhplbq|s_%EmzT?JQ(l>yRGtnKLZAmUx7b9%KPqopewL+4xSgBSAqgo^OrLx(sda$i17@&I|9XE`E2U_#G>`kbvHK$^UE){gUkWPllPoy z`9117%iK}QKh%GPNBXOF01}X?y>aW0~&3VQl^zlPhzDb(T2@{h`1uCLZG{ z24v;}C_qKcOatwElt7&qJgOCIkMKG9|D_}u4+MsAT9wAEQTCh3()bDOj6JX-(G`(r z8~Pl!=v=EF#cQdvrOXKUe=`|c?rQ^!hi3`;41NcvSP?uAt)Y2j$-E zc?!_4*1PCuW_{q8m9$v_yf0G3YK3rZV$E7V3&-?>e_6!m(yGeq6|{2gB2%}1@YDYt z7e?dmwSqS;aL|JGI}_(ewV7q$lu_5K$ z@`T_eGR7c1?_GK^(N&r!W@9dRDN#!2`iI8o@Rot_oxcg9X_u1m^ z{lz`2c|@~K#oZqjcYnc`H{|i|UVf2B^6z1u(vn_>wd0xMo^{3DJBqva7I*bAk<)#Z zcG@ct{2P;%!&QRkJAKabhw%X}pBVhGhvHuS(5LSX{PeyeeN_MDC*El-9iJLH1eTyQ z{*ekK0yKG}?ODd?R7_m7b`zT)oBv=_9ASk@>|$Yo5JzlTTiOL6yVh~x`Q=Q~tv@q}}Vr^-p~ zKTzC#O5riknc{B1TZ~k60`d^;K@_Cv#gC9>J|Ka-!5$#|u*+a{NF~3;0u?RTQW{aX zDa^lnmgS3JFM}L4eM9&|U%+qDRwp4o0LytA3$@y)iZv>`L%>~$b{Wcdcu1(E`Qj{fiOd|?G`N|JzYAT5$oG3bxTKm{O@+YT?B@xQnd4#77Bu-ADe|K?aYuw9$? zs>ILw49BREsFe_ePxsW%*oIQ6>Uuy)uqs$03@iqe?p>-beIn^+^Y8z=V1ySET~)$h zyXX_H$=x($AEg!LHvVL{VvcnJOnR3kz~KEk>_(MJ`6xHq3Oxe~PwHGH*~h^Yp`ev^Oa z3Wr!OTnhLp++a2Dz1dF32eWdw5}DCh-Taux4kY=mCl+{Q)NT_zVoY?2?}$jm&64)m zzdO^7KM&}fv3-wvk#6*aRYU-HK0Rjs8&Fk*zn1^Mgj=Fc;a2HazA9T($(b1mTt)Nk zA8X5IP#R!|VjUr@hYX&M#UNphS!&SOIC&8wU=eL4W`L|=kP~O=L`T0ctgS+tNgnWq zFS`I)HFG>%e}(*q728zzSR#nK!k=TWYQLVY!z$z1l`@39blF2X)7hc4jAo7Hjaj9L z-uT6eH)FwcLYEOogR_nCk+@8&ZsCsA2+{IF^+lFE3?Xtg>mQnoVSQ6FTtg+?#t2yp z84-dc>ko?w0AbB8!>X~Yb;fxm5Jz9@IM>|et!AvfL5`}e;Io%qJpQ0^Ol88y(HEC= zH_gl7=vbOy^b^1g2Vt6-S^R71;F93V*KU==`>1(3zhPAMfq=0sR%j@?$scB0Lr>*W zxe^uh;(gV7S#Swu_e>iLJ~hFp1Ouz1&8kbRM^u8>fuPZ#5GyxL?tZppzi&Yb9gH#T zQCuPNGoyQ>fce$0Uy5k{Y(w)fcsVQuBKtZr=9g@pGv~!%UotKV zCn((P5-gT$CbxT8XiaUsTC;T z90o;VFBiqq*;Y!ZP)d>LO`EcO*Ilz?T)_}E_)Cjw51vd@jkPzsX9nrR63}CMAEUtBA6x`<6b*(yB59bK+!tMBqUNM0=XU%G@5~_gLW4d2Y|4*m;eb?G&y!YH1(Bz;0i&@1z=j^@qTEF#MYoGb3Jsz0EoV%?Q zKyI(Ta-!dZ)qL3acoR3%l$7!u|4pICUY)dpFJ-tc&slSuE+3Rg6y{m8N?c!^G)VD* znaPoc7bJq*a|6y-U`px34Yzr*k)f<4$t6`?lzC(|mExgWNzL%bevEzO2P>7<1#BI-Q&Dm&cEQVd@YmH9GWWM#x^X_QT<)HhFbV^mAs`B(W z_g#g*Dem~n3nnre^1YLhv%QxUC*`XdJiA4elPGg%p}*kxd6Q6exVbN|y`rkUVpV&^ z{`QLX?G_)v9`TpHS0t5Jf^L-Xsap~*68wP{ae#svC-{?D(-Z+XSUYy_KHef z|EAXg)w|rajInAsTWG`3uj%OFC&s)%WkfXldd$GA3Xc6c+`cV%e(%=q&E=I*<)a*9 zvEp^r2nHA>gJSQStTn@L=ATWv?yV4G6hqU}_yVL=;u&30Wx9Y6`u7-3tlFv`@dGDb zGi${?@zS#z=TJ*en$g)rYM&YhTt@Z!JbDq0pyjX2;IuIKm@&|bE-*KWXztkRHQm-; zu|fN=fgsV2K4_tv0APNx&6vdKuz}w+BI4IQ7R;e2MEucFX6S=`+uJMN(yppwF6BGf24p@U9G{Q1g88d{X;wsK;;~%G~r#qMW*Sn3LF$1^y4%2ZB)Io?L;CknU zr9$kRI0Nj=NbJ>ypwD(EVtLln_MiUIxPgyYXFS2H9{VuCKIJAG_<$pSje{^xG8iP# zjoTi$G?HX78#eI|@r5pA=}!G&GLF8ibm-aUBBK0G@S(w*n%f|o?^9tvqy5cBrAeI-hBQf3` zUH9%bUJh*Ydf;We-FexG#nMmST3<&WKD0o0*&;8B&a>`~_hO7J?P3jY8Ad;E_^&fZ z!@O5|vA$WFm%hszh&jRW<>)cw{qA9v6(=gJV*97cM_%8*2(fV!kNLy|N)Pdd<-^FK z6Xo(E>liOjZ#`k_R_{08Tfms65LwmZ7O@so0771$9EAzvRmga}lYE`DlHa`X|J~XX zi{7oJ!+W~{ypcuw-CAd5!+X0W9s+|X1#p4CttE3N&S8R!)`@wd(fZnRL8^A!2amwG zt@Yh)0*AV-*tuHe#rq}({jM~i!W4N&xUc}GC>HbhtV2&mg+79h_1K?u*BU;8Kr|hO z%loH=e6~=M_m2~<`9kCq6#!Sk+sU1HAC*^^^Su!nHDoSdd;g>?$oN2lgCiF3YWrq} z&S`{c#J+2QAC(uSw zk(EFheX+iYA)DF`$-&{u5KST#;4D~GC=C}2xdOv$?rCk2Uy_Sd3jw?BkO1!{V5S1m zCH(U09EQtR0H{NkUeQJ!MUzx5LaUKt1@KtkDE#EX36^52(@Tv z5p7#qL+9(;x30Awb#g)nKG?oxzS==+G%ju5y0CrAtEvubJhN7}Z!M4MIEUM}E)t&{ zhcKVt^V+w(wTHqBbfr{f{jpOqhUvKRD*2=&>;zQvz9;&LJkDQtxIoG{($nEIuS@zUEm-FCSnyXE#X;){Q-P> z6be=3Pra_*9_>PC<7hwSu~lb>DqvAo#9|Y2xE8GyrQPwsy2}P7(#?lU7fm1!>-6O? zK;~L0Zv?_m5uG#v(@b|7BlA0$XgYcMS>~l%SWzg^go9fdnA}-w4ZP3ess12a8IsHu zmUU~c^;NsVoBZ7vU=2>7MP`0o=~W=`Xx25R6hRA_aovvRHM7LTi{kRHI7NG1`xZ0J z8kd<7umxvfv_Qdx!5Ef6N?BtO$J zzs(qM2FTuQ-%6J8n{rU8LsB3pADIO~RiPorKF$^Q=fXqd0cK`*DU>N}a(8W{P@iYE zT94R=&Uca}kiWlO`0n{3Y#ToNygmO|RJWeBKR935%*+ORbTSbdk)RN$dymNoXRlCN zOE+pnaNi$#k_aRol!UE5C$ymSsC+A`FZR%yPhdQ&-&fQ)ZwH_B!Ljuk9#V!U5wXEaqmA|p)S=W7|bKb6wV++o`xwyOLfA{usRo=N|#o3A@=gOCzKC)R<+%`j3 zpWAFR?CDm!!(P_8cwI;JMt+>xRMW9!MMvGn&dqx|*VcBfY&^4Z{%`E%!7~q?n^$x! z+wdEE1kg6X>GghR0EW6`f0#b?)AZT^%(`&Tf073pJ)e$I)ngH%&D9Iu15;zH#i_ zro(3!?D+Uv2ah^uZva3nJ9DJwbnDX2`Zb-KmoQZ4@wueBSK5`5^GZ}K_orLwAy{+@r(3cWoCTt8ZV{EoNE3sfB z?as7pl(9c^$(iPQ3FPwHvwL`W)iK48tP8MB%%V-{cX>8%9Q_0DJG0?%$Aax=mK+2f z13~A8d2r~=+O4JyR^>!0d?nks*0Jc&nUzORx31`1|7u6&%5zoA#jm?;J4knhtP6Ke zA6aPV;RbStDAY{o++Xcde_qFqd0=Q*ZX$Yi@gmdZ?6xE4>^I2-lNe${AP0JgXGRX( zIKdc|%W#vno%^?SY~E!?kT};Y?_9hpR~ihwK9{nf8m{4rN=?1ft^3JxxM^KUHPM__2W`0#? z2KXLS4om?nV)Xn89JR7OE(`%w`@o^ z*QQ(6rkh)3yRKT9Zn4wN`_nB;)6E;xEi2Q_N75~?rJE11ndLR<=EJ&74;GiQc7gP0 zDQDr=_6pGGQ>t29!R&WQrp((0#;*y@vynh zRdN7@Y{s|+rpsn=Upn$xfT6s1A@F^_9*m8$S3`!% z!!aERm4pyL7}hsg7Urpm^uo0|hA>S8Qlg@M$Ocz;Gfp`$2#P_{1wB%o(#~i@&k;|9 zi{kw@qig6th88eHF_%q<;n8P`}s!!A;Sa{0Dp~_Eg7O@B@%Q(8*G!h zNUP9j(n;5{@eP+}V0VCfi-xOmIH7~L2>bjnWGZ48Rx6TPP1)f!N;n@Au$Xd(@`aB#Z$Ev-*dB*=(2 z(k_@(!N1AVcsDHW_Y+#GaomN^n^pE2koYs>^eiINF|?U;MW zy5&2$kWs#yDk_A50laX<$uy`UTlB9~RltEw)E8L0RyzX6(mboM{L?zk_FxP*m5DQ| zKo`o$p2`AYW%FSkOqUs!ocDRGQ;!ZV02(Qsf`S^CU-P~odp1&intCz zpauY7DA0lj0Y{&JfyGjmJcuYBp~H;eEXzHMrk@%lHAzW=N|5yS)tnhm@aDo?MJ_ZM zTTJMws&tFMrbP^cdok^_u={oWgj`nW@P;?NGDn^<5+ubC>T~xyu@Ir_J+kw3?V1O2 zxz;Vf!p)7=kO$QdQy$=jvsXZG0!(_aH*4}w{;oIWg=T@>(~GWBX2CLA@E0yhIw(C3 zSeM`B7^sz85>u1e!5l^g3lkc=j$bwJ&yqW3* zo*%gfYav_L^DlR9g^oLTm$&&=h1|Czx3R?Zej&M~jvIQoo2Z`q@3?KOt=?$lo*mKN z6ccTkLvycTPe&azv~5+$?DZkDtl9QET626an=nk>(%VyG_;wVdnoevMV=6FM?qTGX zE#rJJ_8lAH)%+ z$bHt3L^4U3qHH`W@G8YMd?(fmCW3tBNEhR)loW2H){UN}@KI8-RNYLa4@ysXZBg z*d1-J`9qr6c5AjZ`iJ3OQe?nH|BzdOc4rsB+QfUpi zzHJLVP;4?u>Vy-*z>HyCbeR-vlVK#B7-$U`nzha_+Ke0cK;wtIKUf^vg^8Wo`O)$Z zj>bOR%|G)`?f7U7Yh-yb%LikpYEK>baQCU5rw+tED*tHBM{BLIMSRcj)V@=@VyE_e zxI1?0EgFZ;jyej1T0U4v=j9(BViXj8F#n_Fr}i+AM(xxdSC!vtAx+lAKCJy{IRjoT zAI%MopiTt!i(1idy=?!S#;P~u5F2;L701D;m?gtBG%vweaSfuDK{$TzGN5SJ% zgMdyC`n5Q{#2fMb%eWIHPr%X-%1<3sTRiU{|6z7$y6f!O9uAEYuZ#%MW~cZQ3}+xv zx4FRMPMt*L)IsqK3Z1F}-kk!OqCjX*?f7VUm+lGBr<#D;b8qZSH?}#P0$_&Qb?Oi! zLo?4xpH8O;qJ&dftIa>^YBVim z&>A3cQ3r&J2b?+t@moS|t^215*^EAu^5T(j{8S?*2gsf?T9S?~i9gafu;x^=<|6EI zE6%7CBjr${@Zrt@09}lUMvZVXSkKgHQ_&cK^05&2Tr0g1A*X@Oy6jqjl<1(7@&{g$ zk1>GJEQPrvwF-VL?-{_Yw`w1$<(J(o5cJdGIY1C!gT_5$Z}7S}(|5H1yTSn&&K7Nz$qHWKI zN3}n0AB5KAj&QsI2gwpB`~&+$H;HU2@lK4`f2s+M2Q&ku#49PX3x|_|2K#*kZy{M@ zvYE7HS;~sI0LAx6s=DRKNlom_m=pwiGJLVjH6QN&a3N&ta&qW@MNVj}FANOQ$xUYK z(U<9xF?r`8Rj|KjyD0MKZ#fkafx6Z0hTVs{`1CNu8s^UC%1$ zC+kjDojiJS`^kO$tvXqAa&LH7Ot&|(rS@di`}WCgCwIk89-{fN_vgn>?u?z>t*dG9 zemM&Ej<6n@8LgLo2T_iOR`k?pw_52EJK1=0@5$zq2j5>LO@a!WPi|+J(2iTSJtM5k zulwb}fEn~Uxi8e~)|0%Be`EQj(UxI>fFM5D;#`$3HlI9U+7w@K)mm@xpc?XXDAY ztQ+n>xe~|fS*(U(!hzoCww||Ni{?k9M<&S4@0a&xkiFsfA5=CG_5;EV6BnV*egbtw zgWWjdkHD-$&`XHkBD8VM%0#=Dk+kkBI=K*yT5}9>TcE{JDKAur%~~rtQ@=dSx`Vf(QG*ex zi*A}qx5H*kr!076?j_+ySmR$gxfBbe_+(a_W7yTi`h9G{K5<(!`un}2o0JsIHne0H zi4jaRCs)hhWDx@#(R>9pMzThioDUiq#k<#tTtA{0DVu5X$k~yU5(tDlI%B!BkCs;{ zz9x?kYeABdA#<7o#E1+|IWvIJFHEhzLn)-r5JKPsXq6nUS8|nGw?6vI14KaL+;s9- zjBU*)t55DFtZ(!toH7ChffpYCHo8y&NMIu4CnE@JWEz9f%p|=SZg^;_aw?RYbACw# zxs$c<#~AlmcOYqQ4gO-}77t=-`N^Yl6I^H?GCp%=tlh3^w^y~>N7`+> z-FA*Z+U+gv_EK5Y%?sP@`R#TK%kB1tcKhvi`)GI#omtP;R{hbee`!;zsu$>{au!jy zxt#~~WCO!i%7*fl?d8jOU)ImFOf!S;L+g2)vAW%s{_QrSV>VuRMs89sumvmj;=DQb z%J3X(F;(pp%e~)t>%haWt-1jW(XGnxXV@h5aILOf({3{wAQ{hXR^kz;9#Hd)RiH#8 ztYx#bqXoLNk)@Gnm9HzB*I5Nk#zxVus=yyTz>M#Q^|!Ic1X~6*L!i(!-J%8omiZCh zZEUySFau{9j+OKW8h$X2!JA>7z+sYcn^gu#)C+io9Rpa4#dZ3FwKZz`MqT50s+$4~ z4Hy6=*QvYMRpC(#(_Bo@Y@aM_1|_1 zm9D}e(G+Vhr-y+wBa{({Fa(yO*-IqHJCd?0SO$BAGg=udL-A@i25P=fY>>uukHW#< zDCwHcgYVMP3rGw}EC2v#y>!BV6XSA?17UGuY~A3#uO|g0% z9;|?YizX}t+3?08JAfD(U^_aAFzs*!W7VPZrJ)(=JVJqeN7dL*5c}`g9bp&o$ymQ$ zBWiyCU*PEPiz{v#KWx9#ZdWUK(1}p-7dAl#ld$_@noCfD`M{(<1wwkW!PF^__uga} zj<}XI0%B+e|Dvl6%E%OyJM}42Icj{?Q#lyhRIR;KPV2I-s@cYJLwA#NVp+7kJO%p` zbp)5leo8Gv7_E>NMr19Cm}L{HbLCPsOV*kW13HrpSVnV zV7$RRz(#vTxj9?wl@qs?nfLwnu7EHuu9~?b)4DokhVJG%W*93ex~=WyOR*BOoanJY z>}(ASe=!^n_)DNN35F7KkC5}ji_U77^%3Flu%Ls?8;nJS7zG3Q;q7tL&Qv2-8eha7 zTBDpQ%qoIOs(8DPm~T`#Q+@ zkK4!2dq-Nqa6CbM_8=i>)r2szpUiIdEy>8_=*@vfF!v)pap8Kw{@Xz2JKh+25KFJH zpo8Q(8eWr)kC$qi{1E)SLxBm5`TIck<`+JuQMueEdzZjTd6Bgoj0KNBNS}H<%Glv? zW5BESC8=cgP_Kd6WE$O^^rrJ0riK4)P}N6N{Q7|sJC~AxhHLMY!#MMThKMJtV;zUq z%7g#_!4AzDM9{-$s6M342= zS!M{+&BivK!sg`>=c*2xmq+j;L?(G=duf&PVEXHCb~aR+cLc~&{k1KpTVL&X+wNGo z`mDX+Z28(V4Tn!3-riArSY92`TI0MrqVJH7Rkb)8po7tB4I9bx@bVsmD&8Tm*tCim z9XHR+Z^mEasPBOQb7=H7i&iX1q z);CQoh#t9P)0^_f0Chb)vin90^9G7DYn#r_U;T0P4SJA)&ek05s9wa2CwN~$$Nu&5 z)V}}XiB+A8TjVtbwJqoDC7sK5yDy%Q^@7D`E)hE`7k9ME8f(aHIe^cA((p+XTHD-bCRr?bYqP@*xXaV}WUYZtaG%wY6AaIGEKorv-h7 zWVc;(2zAzFcgREjM=H9 zxz}sXy|rE(xyN3}s|@^r%ZnI#LRA076Ba_foRoe8JuHkoex~5**Nij*+RO)vAnjX@fj*HSYO=y%i zJ*@w|Sb*VbM7pLX-~u+(F!*qD$~;}OFqq7HDhvl4t+mV4>2iFpR6Pbw7n&N3t>$^tnl&!+bd<&mj1%%#(Kf5V*C-ZHStTC1 zs|cSHuTTkAPaVwFhK8O72>nac7XyH6a&5WT%TT~aAo+`l9u*8mgxQJqQfVs4DaHaY zdRQq|$X`+6p?>9^L9$0#zL=qLhG6*SSoi#}_uV9 z3*h2}#st&4>h5kWHhpmyXi+S*z-jr?T6bLqc`yQVdhAl1;ms%DDSDwL0h1_rRKz}? z;}vQz%U}z_4z^fhvW&kZ{`2-<{4x7Ls4&*FA|513OrbW zha`pK=4*i`#OQ!x<)sjtx4Pp8l3J5@TafrB&H-duL3A+QDI!#yU# zC2lxUq+|;;^U}+s&ZvZ<(Q`PuEagp4SajsvzLb zIQ!33FQZ10RP5NQLk7tZz?=EQ6ngRk9RiU6DWHR(FgFArFGvuW0lPN@c5}|jRL1ep zLm7+AlCYS!AIN+bWse(W>XykSOgv_NWo9>M1$>|`8i3%g8xzT5nci^7v+u^3$~SrTp&D$c;m8uPT)hrntlP-PRYbP1i)v_a?m$ zXv92{2TMSuHE_6Nqo(IPNj%L{L%_@=weHY6z|wV<>AGXy-QnrFru2bD>AJe~0UWAZ zkgnU6K2R=ebyd2qTGrGZ)%7d%_c7YBihi~#t3zM9ZeF@>W4f-2A4UxdT17{lJRonc zPuJCGd&VjMg*x9V@KS%x+ILjbT>fL){3Z8ZyK z%MNivLxUDn5r_ZFJRm3a~;bl&;(F zYdTPFjj-(yp+dRZ8--r9auNq8ozNJNK+6#4>TzaPkVWtZR%5IatNpr`){UMCDl-E3}2{}7!NDPS#Jxou>!l-=Uu(WO=5{QW^k>q9dUZn!D z=F1EO9o0U8n_xg5m*_YDfo&pJ0DhmMj6txI)W~Vy12%|5FBoS6126z9F7X!^*Qq+v zOiag+m;o(5;2b_k zWLWEE5@~=s$uDgx)rSHDXcE-y?k%d#nWqAE%CJ z>pgROH=$xyhNkYP(wzHX8HXMcL(qpJTJtm@+2i3hJDiU5)&%?QKh(VA1;O)Jeq z%S@f}eO@@zjfR=P6T2Ip?IL#2=R6f_WsIJ+O%lObaCT9=^ouzY)~g=JtifL~wkpdd z9|2;qn5bnYqTn3kX6H9dGB&=NZrqh_S|NWMtJ96g%%XQlVBS~VxFFrQM_bivlS=)~ z-$m)h7VS#EdR_E3QR3WgvUAc{rJE0EPx;H{h3UqobYruws!cc6q#KW>8@I72A6Wfw zuHFs0oxd3`W%1O@&|^Q>Fqq4dpdp3$5g zN!&1Wg5CgUsOb?*Bl4VmO5G*U0gr#*<9f;J^GjK5OsI4s?@%R|ck~t3YhJoeg$O&q zy!S@A;1bAZ`gTn>vIll=G?B|ZX3C8?4v?Qtq^xh-=}ZvGG~pR7B-DH1niK_>(F6wT zT@<7tdvn6N7T2MzS)9Pkt>OKKNb@Ac1E@+df|Lt;kn~-H8RrbBScqG17)-=N_77E6-L)!t`veiYrx%I zYr-`u9UMH-<&R|S*qgiwZ4#;VwT`80OOszD0A|Y_B-8=?k5q- z%+%_IRYFMsiJn>I1%!dZbFmEV<~Wu}EM<}YOjZt9RSKh{BSSOAK&F2J2H2517!os7 z1`^GwhfO-Ahiry-7|?9Y=IrU4K{E*MCloVBQ`Fv4Hb7m6YUusFiImjYu#Xe%4yR;E z)!(6<*r6!+WtL7@>;VEzB9^H2dn~4RaJvq8r z3zrEme@*^tdNh?=H@ifjEvlWXXbyE4O-QPdr;u@q{^jyJojIIA z4S{Jy6@`c%DW3kiGK|%2!Nu_k2;1dmm2_7LQz` zglaW9keMOKds>jdCi}(sZg>0!Uf(_On~rkJphiO?+p}~7>PqfxXOB3H9|t8p84%NZ zn%!!TDS7Vhx)86o`*$u$1Uxqy){Wo%gpJh_uh=|k9}~iI!rDQ|or*Q5d+NNa&+u(m zPqC#Kx>yNibgwOtTTMMXO3S#$7`cx~yn7x>*BjzmW{yI3i#t$#h;K$5at-;{2!rA2*Rx_(=_eg|vm{d&5-S{2kv3(>KI z9&$Z$m1?029sTQ(=Hx?{<7N+s)>bp(!F0n?wSYm(oxON5NbIHGLN&PDj47swLG{ML zJZsPm8Qy1jWrjIs{h<5~Q>b0<4MYsns;Xpcaa$Zdst{1`1i}5f*+aq^*jTpo9xI@>d3pI?sH{Gzz;Lm65?*8dUu z@Gbja()AqHf{a+aQyqdE9wt&Hf@CthX;II%YEo5&i6OjMr^+Zf8X8Sxa?&kC5_MC5 z;a6xZZ(Me_WeYGG3WjO|uu@zIvuMv64Qm6bZw%0~A;3V`LP;)*9Qg0jbTf@eyQxQk9KC!<^B@^qK8sXvQ% z?IJ4SCI!vz`6NI1=5BSmWvRafTVJ(^q&$eg30Q$B^$O$XNDC8mVK%vCZuaf;|`>QR)TCe!wciIR0*Jr%pG z>!0WvHHF6^8ywlJIk?4?0jywftTzRq7JYfvRQo?Pc;M+5Pnt38PTe5W6g|lUT)@|T zY8cJY63hnHc*SZ*ct>5D0xX(P0d1M3O`h}D+Y!TByv1iTh7KT^UE|_4U!ZAi|e=oXjJz5Wy-q3eS${w zm`WqsP})sT^xrng9D`KXr>irsl2$K}-Jk6X($#y?)f>~>xoxDHg&pbbE7H}q>FVlq z^)6N|OjkFhtD9LX&1D0(NXgoRbjh3!w}p?#vU~`SRDIN%TRuF9O1io=UA;5lACqnM z619gx_qiK(nsI4cujcaCLqvM4G{E2vj$uEb$!ZYYsjDi(rI10zX=$a+2>>_lMWL;c z5LGVb{H#oGuTTpKhit;CgQ}_4MG&p5V8RK=4{G981#gwC(K(c`dO2m|;L9LqR#3XHABM#9uh?u@th=CX0CA}j27joGS> z_1xaB`F=j;K54(Fun`~==pBl9iyFBV?7T>scu73hDdUNxEI8Rx(12bvVhH(l(G?o?ru6p3>1ru6 zeq(kjAO{Aasa%ptOsNw`gh6aF+00)}^Yh8GP_{9+;omj`7zvD-Qv9wa*qc-*J)RYcxrY z=UFA?SLqzzr9vTxQOGamdP+V8kH3PH$pcVX#-$5qM5lh3X)Uv=`&C7Elp+cX4q&F? z<91V9P%ZdtPS^suIH@ag&g4M`ppL#KbYh(5Y7eILj1MOZbT9)Hj>-eD;(KT}(6iO> z=BRZqiPMA0y=y%(q_@+7^)lnS^LsZF*U+!$3ap7-*VaF5vtIzvnLB+s%{2u}m_`#i z{$Xb4-09GjlfJD4hy_5dmM3|uGxs{!#a(ZvAnOZ5)h+1b)CcDuH{65VI%W82XqvP2 zUC(Ih@tNM`;X?vGiFvH;*sUj)wKec{NInU9xKU+RN+SVMC zkDs!h&jaRJ4@~jZ@~yx+dW)ja-hWpkFv^M(<@%jU`68u$DVb3Z^Isj~H@sWhb}-Mn z>Q27IdPF|u%7-Nnwl&7uUVpdt-C909*l=P6O+7P1)?4-)<%4|l^qZ7N`P+c-iNlPs z#I2+9wMxD_+iV8LEYvsnTaNHOL>X8yQo9?~fyKeyDuMDyObiFaMd}PzqUeZrZS<|p z0cx!6trHdUZA^f}me`2}bhpJ4J`=m5?Vw{1>)+drGtH`&c(Hwv(*o$k7x9RXk(zH6 zgN=O9vEoEUo^_pj@Tzx1MA(Yct>C?aFPkp#M>w&-dc^%)FgywbJec_r>cXx^t5zht zrNY4LG@>UKNcgeu@CiOH+Mw)|zvV(f>&lzDwnsuQUqD@8CG7n^L%Qo^c+W8A!$Sy<3x& z*O9p*+&tn1(ygunfGML|Jx7;zO*ut1kjo9iG|GV#80b=ANM}9?O=|l|FIj;T?r>5` zBs(Nzl+(UL+p0*?!+hIU>ylI?0Yr#Q7wg`s9}kY6Oe5<5uzMZU{ExlyU5Nzb%250_`we@U5 zGvMHIz2rP-=9tnn4FZWhDD;Z5Y>4@yOWQ6C4D8vsUvy!eUxcy0yL`-?!b3_Wo4Vhb zx%R8w43fPcW<6`K_QPyg!C!YrCY*1q7Vu?1jS3Nd4P-VpUWszpC8UFHd>LHJLH4}H zMrW_=%b_E~Y}MI2JT6+YgBRS7wEAA%whdzH>>Vij5-{@F`h1^oHd>cmVKBVa%%g!s z9btXVysTIc9@!nv_}a7{E#x|JBS&r-yYXn?2yCYwY&qxHSq`0i*_7U1&6&k&jgTDp z$pMs%oUZ1ah8&iJ_lLVMp_{=u%H;GC$Eq9(aKuxiN8ECPmxV35;2omL(J}`b7{LEI z^1>LruC|6f>F%4m=hL0jR^1G3#^t1d!Ok4e$icn!!}1Z1=W;zm0Qb(jgOuR89YoyB za?h73EMmC$BJK1L8`rpvHE_b+oSsooMU!`Ax`_o&IN+OcRQlJmE_8{2xUq`xIL@<> zdGZ9{+#`Dl99n3>V^wnIfd#zgLXp_V`JGB#MGt{Bv; zf!GZ+JxDy~WR=6#i~`{h&N~x;eylgAWECDg0RT?syn)kPi_S#*7k@0~bL!SR!I^P^ zq8AR0v^nJjwB4RfRq%xv#K7ddCMD;u0&@0}qe0Vogttow<=boGdC%`wFu z&%!6*tB+Y@?87}}s7FPDjzi3ILMG=Q&!ZiNgqZ`;a=$5kkc@@QiHmE5lmwYxLZmh2 z)0~RWtaifIeqYjvW|;%{Scy`ZM4f@HVGs8RC{02XL|gzcHNKt~K8@~Oq4KZ`76a^Z zu5_B259l`aq_k>Hkt}gRc8C_5fp9-~9UzqV{v-xEH0;4HL(p#bf`G8#W9=+t+zb^} zW90G1(4~UhsieD4fgQQg_I78#Avi;w&kjRZsSGfN`y_&5E`jOYKI~23>Xw(psVgJA z?90p%>oL2vcT8oZkG)4=_#~;U0@%96#2SXt5Zcq~4pv@BkboEx8#Jl;?g%V*8Zg5(ru(LG9%r&{u?hsSIGqEu0= zBoRxzoS0Hp8ZSOx6^q9T6Gf?#*sQXIt8hx9gw?rq*~{!#GpvcF%3_7btCA&XFP@#8 zi^BYbJ4x#)deJYVCrV0>S7B_jWM=C4f#l=@1}kD^B378flG0ROY(lDt#Y9nT3O{f% z#gEv`;?%U_cwsz0RUDfcFOJ7jlS>oDvG~hn`EhPZymsW2(&X%Tajx;L(GPh5Of4&# zl1vpvxu2YkIT)YAi#%)S&?j}=91X1JzUd7U#+jv5tTa)E6dd0@HC2>SI7)FdSyWOQ zFTk^|hkoYSZdJ#Dv$VH*hYfouQ8Fc7Jgp1#9(iP>i3ahTnV6EC3eDh~2K42mM9;)f z!&;Ig6vS~%$&^$;tV72$`<5dO8{J1r8)JRC@)3+q%P`wDi zin|Djke0v$UY_->?;c-*A@Da|oJ_eKqkF#Q3v^1nY*Hmbwv>XmGD+4?AsYx$ysOw> za>$EEk9vBH1=7|Lf>fDX33t6-0VtkET(!T3v2goXRhok}Si>GO|bv ziKn1Wa!OL;R-%p-#UsL$5edyI!13a7<4qCD;ioEBe@hao-nuoD30TA`>DQ&NR9U7y2&#| zw&u3lx~%_5fGZ|CetEL)Fi#pvQqG9aO{U^A!e;>!)5?kx#qrX)iFj;sVmd6$FUzyW zj8VT5b7ekao|(ZsQ(87774GXRjrnSz_1xIxcz)Sj^b8(6#?fCE>T205>=kB+;`rob z0mGvlOX89hvW7ZVoD^00@o6c_>tvl>f;(Ju6UCF0rE|*|tkg9#8&WNRR0;bZ$jAT&^XNwbs@uEa&yeQAQ`s#<{$o9%50S-Gtff_Fy}Gs&uPxHW*W&3P?Q11 zNwHvZVmMGGDK69F$%HXKUPc{cE=$N%CMZmtm?QA#qgN*~(R%;=--cRqOJNaVp256P z2CYnN1)G90TE#||%@8IMP>r=Vli)Jf^m|nLuuzapi6?Pu)TogzrKJu2L|N!S&$uu& zRSL%wg0O@_X#T(h4>8`YjKq|Z@)95(sSBF0!y;{GkPJdt9!u*pQOK0iQeKQ%4?fsK zv;2g~u<4r6RV0^z!X0J{8RF@urF^sdD7>GRD3;8WG@Y9TF?)$|acg>PRCht?ku;sHywJPyJ$od9z+*11&rQsgoQrF!GFz;)S1O630wTE2NsC*HtlPe-=FccjOf4ymmCc+v_4tnBl7g}r$0ET)me|yk1UgwnvfV#Y z`%FuemKDbmGZ=G5VootTy42v<@uSBNxq6twqI4YRKCeMTo;70~ugjQFUa^-3O-dw- zrq3p0n9qVB96$OZ2U%q$@Tw$HXslq*vXmL<_>LL6j#MeiFDuTAjf+o}QA*;4ljBAC zvDwMvb(mRvyaB2g$B)+~3*trW*Cq>MEX1bDQP}ailG2pedDYP8lEpJ#6u-Oy19n&= z9#CUv(+CR{3?Bw^8VI6$Vg_CEtS?-m3MR|YWrfz2LnmT??(xPw5skeZ#6=G@T)~*l zUKj=*-ybVEzMrX5S|^LB=ubZPu@%mIF?A4NzIj&v0momPmSjs% zp>@YSW0jmShsCN%W9cCho(M{g?^gKptOrLu9G}LFpD3D!aT38|w8W=!4CN6*Hoi#V z&4F*8b>W3iBuZx|3ku@aUH6}dDNfc2-LAg&Ing6=@@x<7I#?qgGA)$FLYk5pa^3(i z4b}m?IAWmKMk6_J@c5!4?J7};72@#mh8ZQL)-AUke+>X<%qWe)nfy4X5ehgbp(zuU z0eRLBoP;GzWl&f^L2OLZ{-yt^0aWz@pudNV)2AcxpZT_<3d)RRg%eNNa*AlO)v5w>}rSCD-_U z`aL;Q^3hFss>_8JO;ol(3~Rt3@3)DsDQngP-%zvlc%M@QOi$T|&xsful|ATg&Tdh9 zVu=^KJGs@RE_=DN6B00pgC{w?_lg-&mcP8F6F9p68N zA|MCru|z@i$t@19V(~e8dh6<|Ig-=UTY;${riZhf?6Af@tO#=Smh05kbU83emU42d zz %@PaqTUgMt&iX3Xf)9z4Vq}l1yGX{DltLstZ%pN{_=fU!C@JG~lPH1t=s^_!Zu!T-Kj44P?<2+s|d-JAuo^{{-&kA1y z)bw~Gr#wN)#Xj1UXP%oVC(j6D5@Uq>aylyNG!-lo@223C-$V!$+oG|h9Ig73;y=Zv>|o+*j}){Ew? zTBK!Wsupz#gB&i!W){Rt_y~?nS16aKRa(w6UZJeoe6VWUN z4+Zk9N1k-L7fDl$!z1T9h`KY2GYMR3(5ZP@OZ=QL_wbQz4-5O z9B1-*a>7XAZPwhPQSJI_30L)m)~0vh6n&q*8t&NmBKLyHH^w|G{MUKMkW(iSLp4bZ z!sKKH_~fEnp7q#M?lqH=<5k5;Gd|Ot+gYxZ$dxHQpH3-|O{7JaI{gbJPs@dp(c`)? zHI&0$YK{$)xqzI>?UMD#quM5Xb)-bVH|>J3(U(O+xj15te>`W-WYz|ELh8byJZso>e%;LFw)M^L<{Y%w1wrO8 zIO`N^y;OMPExFu{Q9j(Jnn0Wc2woj=N(tw>#&hv457k_Gyy8l4L78S^;!Ipa@A!?q zT*}~Y>=k^=z4O34=R@hiNh8*|XvvwiyUy%d*75dA`SAM}$8^ryC7*hKb8&ag`2u?9 zk`-qwj&y8oIa{^dA5HXp!`|YrIJeox0>G0VFJ3hYFA!7ir!(N72XO7g!m*(r&bZ%b4P@PNc&gF|bYBu6SM{7gp;%3|h z$#dncov$tGSkQd>@H(?zyuCaxNEJhgy5do5P z`^+V0n(NQD)Sg>jdv;HC^D0q7xpRza$<@p#DK)y&&~>QFQY0AxVCfuHm_rZYU^|TWwVosOQ{5K)9Q2O=_AJinQho?!fy>XFHR~< z6efxb%4TpvaRzg0NsJ3cN!h~*ozu^=#+ffKma>C6BNmtDlM}`4txn?{L?Oq8$s$=N z=j`OxrfFTN8ZzWje{--J`&XF*R+TUVg-rG$?36~iQ*a4llg_L3Lk;aiF1b2 z*vHK)CF~2cD=hcR;8k31tKj&TYXGt7Ws@;Gi6XgBz=alu5qnLAJqfQNMvSkQj9|-510IIlrc>Yd&o5+=ZI6M<{lALX5x1)kT|6p z-YC&7O$tnkm2+)b4d$xBlOt!u0Z5_EPZrGqbb-hC`cm18W%;HX7gid38gk5tC*wujUD2(Hf!rx8RW3!?c+E9N zGloS{*m~p<(}09Zakf5Q0xhvMfTAA+hs{|yla`aYz{{8EF5{vHXLJI}tUK=C6wv@8W?FYb|^3^$Z<2P#Q%8Gc$URglp9RjNp- z;0l13jMNNnE8qk}?qt0D@?3FXztFEK))VIHnHgPq;@7Ioj0{w&Tw&ow)?f6s=VXpG zdGaTlmXt6lX%Z*5Fmrj}=3E%WO7gwNQp6#^DC&ABuepByn9D3{$Pn+hO95x!`RnFY zgS_EG-q;}z_R4d=M|l37*C#AKv5sezgLOOh?k4BCPkEqUUK>%a&zkc*Z{54wShVHo zVQD4L3pbsZ$9d8zy;UH_$djJ$ZbNs=aC1`X#5z_TYHLypbkxHxcs%Ob#2`)jQ1rV8PT23hCg8|(v(f|vbTfuEIqPH<58F0{ zChm7Pi65c}aMlIEiM4Ii_ZT#_9nz<^gRsB1p-n9zAWb}wEwN}ou{@Qo!1MUCf#1Ny zIeGVWFXojU!9nqZ$Vf0HemGWP-SvDR?^zu%F|)Ozas;>POelEW$APxDPb}j}<}gY; zR=h6Ha$dk8WKgw-<*D#;fe*_M8wjndZt21B(jHUCmUY)w9zSnVpyoqQ-ZX)!=6QSJ zh#3;&mSK-Rr`|J8^@N($a{zR5RCSb}SZCe+z4P&w2n0%^`Yd1v#&&&<-O;_z zC)T~YO)>MVnqXH-^@tz?uEUSEW6BT;3x-gBfI<=>1~^a!*pw}l7|oX^WsL+y1_<#c zr#c8E?|aB3(7+qpHabI`D1UDQRsdpK3kB}PN+$t%@5YH`)|Wz`B91IUQhfDo84j;q zRd1tLe55w!S+nf_YRY&hT@0Uaq_QsY_v3jJ#L5bWu4av!&jXT!0DDP^!5H zR$UbF-GZ(`qX#8?aJOkBZ#p17{khh%-~ZoZtH%dvcc+y*&EI?c+9eJfSW9Z4K6_}=S)dJmHhH#s(CdU96TZ2ofo z!GJe8HBH8hODnlj8$F0XmYRhUu5d@U(Cr1;Xch1rlmazy@I*1RI5nF?w4%wxVT8Hf zcEb(P8fDC~83pml;!@Ex>oIeDk^!7^=uLy~4H@gl>^{{6>kA+U-eJn8{KcnTv?jCUa%eG~@`dQ|(wpdk_9`YVZ>pR^tfeHS2*O`)tv z&f>akVf@$jh61jK7na2f3sZqHEqj-}FPPam;!={FYw}%Ff&0Ld#enIML}(`X7Zdzh z;x@N9PQH~aoh|uok|!#+-R|(zC^y+n9qA&!!*_`LZgYhDEfXEtl=&Q(|hJ>}ub>#xtz-m_iWaXw?&))<5uR>reQZvWl%~R-W~eRl@Jv`IWE=`7h6k zvp!)JS*5i4zxRK!Pg&NbxOa+wTR(05{FHUI)yhvec z&we&P$=PW7O-`i>xI;(E7&U-9P(Tp7Bf-TNhlA%%>G?%NWKIyX%U5KUiV? zdmq_i{wMxii`;_Tj*LZ~M`j`w$SR}?sYebWKSh3yyoa1YMBk-I47ne98u>o*60!wp zKz@dNfc!P`J7nMmmNgt1g*=Z;L0&>$MRp)RM&3itAr|=eL%xXIk9-p;LTuy>q!DRD z{ulC@&wxF0C-NjR6d1#^>yS0WFb<?rQ*@nD>bReG}U|C;6oEi9i$Vvc%Wt7hCGAJMYbTvkzXPIj>HC8))-_m zQh{tnjv#5|;=z{nH6($oLw<(*8*=>+xP#0_-ay_#{u#OGa_~oD$Zg07I;qzqY$97KMFeD-R# zArBxAAx|LRMN&uwvKrZh>_Of^&L9^KwX7SEJCG5`800bJdE^D85cvVJ2w9D+N46r( z$j_0#LN2_9num-;zKP66UPBHcA0Yo5=|`c-Lmoz^BR@iRAb*auBfmq2#K<>fEb@KC zM&3k@A#KR7kiSDdKa5(7j6j}1@{u{n5@Zvy4cUkM0_i}0i+t`n^dpZUMaXL8C&=F; zSAG${kwr)&(t!-Q9?l`Nkv+)&K>FNZS>HfjLF$lSBZF?lZ)7I&Ch~LSpOIlV!F6OV zvKrZs{5kSlr2oy>jy#RLgltFNLH-8me~V?^jeG|wM;efyA|E1uh5R$}sV`a97m%+Y z&mc394ahr4CvxqVE$ca?2>B7R0@;AM(K_@+cBVeu%6?b|F7T{u22Iq;DRvM#dpikslzhB5xs$$X_6TjePz#xQC2F zotG+^QMaqy>$S&k($ZwE;LN5C%xrU5JoRY)t+hMY$J4Hwe}5WCZdYl0@bs zn~@sir^x%r-yj!0K#m}HBab7KkWyqdvK@IFc^~;3>Aqs5)=SU~=xsl+Dj7GkV%t96;Zy`TJ&LNkKqHZAfBjb^0kV!}Z zG6z|LY({n?Eyz!iQ%EQBPspc7Q$LVfkgp*lk*AQ!$SmX~WFE2!sX~5?{4Zp{L)ebI zfY``Z@$hOy)@G80*YG$ZGbPd{u~*CAg;9zwo{ zyn-|#e~nx{4!n@%$Pwh9kuQ&Den2)NzeN5M`N|{I8)QCGg&aYCg<#79%Z42Xf&P%z?=FkUv3ckav+!JxNX=(~xDz zPNWU_TV%)t{6c0SKSY)wdy#jLvq- zJc7J{6eEj}H;@M89pof(7WogP&v)SiatHDa{}6&Z(o2Ps5WAoa+*$ghz9K>EHw%#fRrdyp~6v&bx@0(k@3hx`Od zBY%VZCo*6XeUOpJH<1FQ0@;MrAjgr9kWS>c$bTT8`#$p_at-oj1*8BeL2P6t@&;0aG$X%2evSMia`6;mh}?}lh>SrV zL%xGdMSh4ZLN+58UpzTJWyZAPR9R6zxA6E26S+mGlw;`p+hou~)aefngq7(6)1Iikc!d0egZX-2hn@$COG?bf{`~{(C&cr)%V?VQg)i{vVxhYDtgF0-_gIn=n|Yq&Ya2nT;fGj68JYgRm@w< zcxI#EAtyS0`=X$f2Tr{;{rXK$#0lIeKfHbVh_=9rfdgN{yVOe~iwKIKYup+%NZO4D z(ua~Ia^59>WWmhoacjVUnfT6wQVH2MaV8J7;V(9_#7njk`J?7Ml$aVXD=6h`qCE99 zXB=l>u$O1|P!6Wg#3!2}1`Z6a^UxkND7f0^*A-Wo^ zC-Zqb!!y&lg_ASee&gia1pM@tU2KO8@m7rw<9GSxX3OK8NXiJ3YlORLw4QkC+t=v; zvyE9-Ug@tH%|mnv!+@~Ok_dsYxoF60P1C?O*I3!6`aCWLw@l=nKnZV4(1r=AnPoGd zS5_Ds`t_TvoYbX>oI@|LF2B4)9*EQjJTnk+88sSq^1!OZi`3-_*U}J&AL9jX2^~uC z$=a;L_?rg|2=_Kt^y?>U71s&H@V9u5b=6gws~iG9SyV8G`?fN-@_>@u@k-E3X7bQ? zqFB5!ZsVg_^$=C*q0~!7{-!IhEFl%AOdnZRni|cEzj%wCmcr+fiI)@`*(lw}EJ*KF z*8u}eKWV3-kt~w2Rhz7RIHjuw4)j+|)Q!42*#Egya*AdlN$EEplbsl^%ZG zGTltmXJq=|#Vxs8OmyZLxWToo(h0nQCBbW~^8En}3nDfg{YcZW+e- zM!G&23PMk2Gkm=Zc$CdTP0%3rbX z>D5<@*<1u;V)3%b2WaqM7a*Bs{1Eb5fcWH+Nt5D}CrwTtAa87+9wzNmyJ52<^B!EU&ri)I0Jc_cV27>jwmLoEUW_|CgZ zqCvXx#!OYgb^(Px48aC|X#Lm+w+9q_@r!08msyi0d(=|D4ccyObGA~AmZNNPY0;!9 z&@G>LAxz3QdqCOBa<|H@Y-)<#R-hN!hAayy3$-%JuDVLy3^ntWI9$u#n%ffD^XuM{ zP%ER%fl}}ZK<#9vZ<525E}9v2PVQ#3D^1M|V07Je>U^#?Mv=q){j_z(V5r;SE07eIU&Y?ccJ?xb6 zSW(b-DVu4 zIkkiFr=_yAW|~;YTsNtZR{^HjU6Z4vK&<`2bF?zbzVsz`@a$#=!GO*$f4OIkjcO;E za79&{>g_YasaO%4O?M7ooOqfTxRss`(LwPEFk5y4omOrwqFZpa5+D#!r#>dxO$(-@ zZ>}@%MK&-7JKU7ne3CaoD|+mIt1r6A*&7PL>Hw9!)#!DSK{p308he?()&ib~2^N{q zkiiY6S_X#YX=~o9_Yb&P>=< zJEJh@ny1i@qeHu}o&XV?8mW|Z_aE8kC`uFrjB)ZmXCq^Y6Cd|f$fU{B0xBFzWNkEE z9V@)8{)vr%3df3^jf^U%o_nndd62QJP}Oi#qlV1eHq#t02F7seQFIG4fHU)WO-d3R zzEJ?@1k_~ulhGz*sgvCv_*zRHEHk&6j_yXY8$apJdnV~YtMM^=BlpQ9ip@sHcIS{* zX1wg(6vy^lZHx&Kjhs0vfPxdSpr%lx5T1cn!K^p=n>}2pO&CuH7M%0bAOjV5TP_Pi zH9`ZDZ9%AwQRIxm2@xXV9KZ?4VuyP;A{$MfvOgE}!rco9HOSdBIJ!HFO3$()PkE@x zO*bj^j{O3_}_eU4_X?3Z@o3TX|Wz1Wm7Bf|FHKaaBfwF`+gv_6j~sZ zvKI*ZUc$aZ*msERDmv*hUFa4%Eu{z&6%bi8Dk>^!R8$nusHmu*0ofGLsHmu@VG&SK zqoSgs{@-)&^JX%cnK1bK2=e{keEK$d?m2hK$-U>fTQbweTtA*c?-APXbntWDWtU!a z7&<~ci_zZh(7Mq&u>JNUPkd}8i`#mz1=zzG zagrT%;|c35XV~djx>!Hl*%y8}vR`N6rE7_TV8VoO z(4bS`E5elnyR2`$%ZCQg=4d zhquEH&sQzl7~^T~xZ~I=$E~>a*3VZvuDAK-qtxq|^A=n5tP@YD-Co@d5*Lp;4fb%O z_SkaEQD#J?cv7R*a_16FYpbnBnU-tC6C3Gs4D0FWpJQD5yr1LHY8|aP(&so*<#_o< z`W%PWj_Zx|IY#w5<~-78&`~Fz&`6(SR4FbVbsEq2IY!fX-p?_r{vcDf&7}H{G5+#Ma-xd(>1as`l&}vbjBRL z>u?HVhRzABvdVIe5IvRpbt`(*QODCcrrT2 z9>34dX5bigVCIs3d2FyHy^}Yrpf8-V2v@)+PmbnEg@JkDvQdhIy&(fVhNm8yPJgE* z9-DnP&i6-c8LdkLeY@!!Qqk4RuwJl_7qupDHlAZ&`)EVo4vIcie*(H#uhZ58{Y%5w zo(81xcJohPpbHwIUD{O_=+86ETG6+pe~$JL^drc#!s^j3UAA2i)Pb99!UtG{ay&VPly1pR>wjXn_8OOLOk<*<98z9j4(Xir-kVaIZ6rn>N@{T0_& zC&K03XdPRqA5zg(m3HxvEi=9<6V=mBP~XhZ=pD26TkRWIrXT$r7|^~9m$jo&+Re7k zI`okG{@4!YUj=NWAh>#jSjLNt7})#8tT$>QZ|eOB zZ|M@Z*0-p?f7U?XvXXu^roS)PLWkKSjnr8q z8-5Hh>tZPIU1#>y7#5;uQ@%52=moPe=rQfh=uPM=dx8J_kDE*6~bt=A!tv@p~ zhPu&Ix7%(kHKS!d_~4#Z!-_t%?V=xr)wVOMZ^nwgg#&X^?Y-0y-!*&ReY}Th(|XO$ zm1BWN``NqfGUgHF5nazt^={JkEXMGO>8hH(Lp4j?+01a~OT4D+x@+$R>KbJXvx(Qn z=(AP_))(I*)Vrbd{YD+3%#S;wc)5BvRM!a6QtiKguXoa8gNep|p80j`JLnzhBHWTx z?=ix0fjY*%+2Jq5%!=Pr?+vPZjA*fXfBMT7&0nOe&3*Iq2Pyh>;h|Rp=(L3XeuMtP zlb2@aoyS~#EQ=ENK4aRp-OGfYs`s|-nqysnXoU-t?Y$L8lO0?+r%a(Gh8`2QkC%On z7u_cif0UbU$|%FjwA-nBv3yBZ3REZS-9;HwyBPDLT~F_+1PxMUS!qZGU$c!XM7vJy z>n@!Wl1e-FL8Cpqa4}4Gb+m^M+qY9k-rpBaFmQ>*GG_lTIgHH<1nQt;y-b_sO(tR4Vo9-c9X{>C|8N9%UG?D4gtx zUoKstBaG-&Pv0`#&7%))u+94x&RL?1o68q1SUg?lE7hIEW9p+Aty24NNQVSnbr$M- znc*|<7#!|z(4I)25B$_^MW>k9?@j3(W3SrnQ&O(4Ly8gV>o9lryz}(M_vzX#idtmrJ94j;Nvb*yDLe#Mnbd)3z~WH<%7td#7<%)i+(I(8A4!p#BQv z%>D&BB7_&u*Zv@{+dG#NCwhpE6}9^bEnDQhQ=Lg3HZ1NqR$GmCsqek6u?DYoabk&7 zuN#fx9qMRTuzj^yM@d75vl|s34NRFbLfI@W6NA-F@%J!wXuz=kMN9MtR{O$Ar@fxV z;hy&+~hJx>?xqhljA zK)eu95z8EHl;LKwXz`*F{lI2utf52tv=^_Vqy>Y^64hNeZ`LdwS+?h@KD1w#2I3V? zo%vFo24G4ow>F3V>8i0@f4fn~JY9u@Ygc&R?WKqhk~-dtKC*cEx=Z@P(zn~Ib6)Ls z9Z(e=2x;Ba3KUOeaJJeI`WKdTjzF6?yLB6E5FI;4L)>eWbZ^tl6?$`nMT1=gh3)Y| zU%)Ps?(NpTlGZrJ8*#I3PgSMi*6Zlw8{DSjQKOGGG*KJFAL`XP_UPzE{qK}1aS12O zbQ~BhvPX#5uJ93g%A0QL5yFW$*bgs<)|Su}lt z8*l1V508%xqTA5*u4l~(HzujGii^FA-f@f=R-otzOfu8mzH{f5+O>zh6P?QNn&9Q` zc%Ld=d+m5y;T)Ymz=;!eR!|>FxDR-i`tU$eEuGm6uiZbayKbN*x@@d-LeVj4Tx-oW z9EbPgRDI%ep1 z)jmVUZ1#k9)%nht^ifx$_q5cY?Jl3@;lzRo+$BJ|h?`5!U05k4DDtdK2th zcDG>rn&c*%44Ht3TiUYc&~hzq`0GMp-d!I`)Q8Vg*BVyqj%6w>o1xBK-WxJB^f$vM zp*2E(Ge@gR*IFF?q)FEVbbE311)w2Q)nCSlH>-~Mhl>@W>}U3u!Uxdx zKI4(1Zn}GAqDcFtT_2227nb_MqQ<*LLuMDBgz0(1Gt}DAacOjFKEB@Er*3`9lwm_d_c&?N;9%8SV~s%!r-(bpYOiKtl^U!T zU9FB!ICqX6Ccg5@i^5sx_K0$sP91NwQRe{dCe116oPGFWfL4_ug*xcdCvmEJ<5QMS zUl?}l2gi*2oY3754%0{7S%ux7A;U`3R~)Z{Hob$v(RAeL*>Ak@;9$w9f8M#B^Uq`k zOIe9J-(B=Ut+UQxo%T+aR*b=+a`dwPXwN;C;=1d0m&NMqT*P>sMY>BsA5narY=C3? z&;X(98;}XKlNy#W##rFmx0*cJg9f#!C5m^k`t&<%^A-#}uv>fWA!TzH>t2U-*Bvs< z-9q>9_KG=mD)n76?1bs=RIcu9xn+0p!s+KlTbE9T>6eYdZtZ~1Bn+z+U4RG|h|bf6 zvFS^~8Z%Oz1^W4Moj}-Zv+hEzm)hSCS4ec_bVaz2Vx$`S%`2ViU!mJ~yGx_L38=3i zOb_4sTeM8~b*L+AH%{Drhy6H*ti%q>=&nd#&LcWzi%COCnczsD8;%Q$Hs@lGhh0wVjPvREoE$=v>#VzHlanYxTjS z8Yi6b8akXa66>uuq%0gV&*{@2(Uz}9D2V!v?&(G2EQ{N$tIW5j=})ukx~#s!*0CHe zqvso~FjDi-cfiqmwDT5yp|E4B{rYjgu4UJseA6K}vk8~&2HQfrh&o%jNC&fPt<^bP z#{}xqJBI`?kD{jH%39Q3GFud|*H(uWU>&v0rPwE}mHp|$v!V6v`Z@jlA>>vs?4^6UsBMB*B{ zVs&gGL*M4$`G}!2Zg>1@@8}oj!hvhpGtpJ-XkVwjR~@=v9k;X(Z>CJ?E{_gyw%oFN z@X*r_@g_aIR{Qd2+o}UPd)qZFpO9qD3`b^am##`$N-02J?hMyD1{Xi<7wM~!LkD)A zCD4j7Qt67}i{V!8ymYRwhDMVPomuA@xTuSdZVOm%y^b23G>eXPy;RYtgXazCy1Z0T zX?*UCy9_!e*ZDpeZ=;Pm%G>7ⅅOLO*DQxbjIF^iARplzYWY`G_`efdu3Efx7Kq% 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�-ptO1VbCq!Ej1Hjc|EU` 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≤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 z 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%0DZHH9V@xo;BW}1Mn^LJl^-6!Q1km5^ty3sG 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

      !Lkp&cu!y)wrEfIa8SKuhjsHQ3?D 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 d(OBs%rWJ99s=jI%=$ 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

        {*`VnG6un69TGqfflcEtAz?G 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

        ^nUDFxbFM9 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 literal 0 HcmV?d00001 diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/images/android-icon.png b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/public/images/android-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..580a92410d180dab2ef940847fc142edf15188c6 GIT binary patch literal 7932 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

        Vc^;!bo|~-Y422zC){_l(~(|I(x$a9ldb3 zVFi{&bDCg(mKVDUwzA84>e#viX*tlX#205@jOOn;d7(Bm0w- z4U918xyvsa1=`np@!7ZmIS{bYkw88Z2rf=i-+`?!$mk-e9tW267w`OT{3()?v;6gg zMeaAvMaG(MZesEehjX+|!RW2@a>|9FoUK+*Ncvl59ze!6jQ?ORiso2`~TFNOpoc((a_Wy-##USKN{xplzo655oMW--U3Y zR0?Uhpq+ems|}78mkc84Dlco<8Z@@Nw1^Y1+t451ML2gEXiw1t4^O6}7~PnpAmX1b zmaNTVKEIs|Sw=E9ai^GL>u*1mF%jp0>Mmq?Wpt%+Kpl1q&RYgGFM zO$)nyJBPNbU3R#7@{zJh{s>>@j zI&m%b)b|E9tfjkC)^hHXB`N|vd2z+FW2^I3UUg0m9uon`X;KtoZ*gleS1P`EYXWnn z?Hms(foCB^`MqwzbiomX_`$Cl=HS07^U*e4C0_d?+G~DR=sEY-OdLn>$Q32^WMa#g zf`-->_kSw14^vUd7?;zjn7=abyIH5uX^b>}7MvpMOtppgluaAP@XDy`$+^d63$~n# z#aQO}XholG$^Cm4;LQb)7l#H2HaW12f5`5Kq<`t~p8E1^<8Hk{w(k|Y@Nu9X*Rs7^InTCPngC_l5on`u znPMkMFqYvHJK{|_abETEgm7Y~vAfp~&$!ZtX59Il910!&~R|yYZ z@xs0@%r*{N)cwT6Ib-olT6kVMWjr68F|@b3HI6CdY|aduA5HgP;tyJ<2U4sndl(3p z9zJ>fsC8sv&w(WKqG`BY$cCxX{0D3Wz1h9cqKkX*!819(q4C{h_j)y}fAJX)qWz$Z zwf4eh;}_J%4dVP42Nha&ooiHgjtk^B4$J$ghi|>($9AZi1cAr49zHrb5SAue1QLdg zIu6GtCU&omfVS6qelX_Zx1qE=+HOMu#fAy<`9}}Ac8tS7NQN4n1NkF3K}NoL$--Em9#{j$=OUloSwW+H+Er+ z7sEo;t;RX}c4Iay0M4+ZFe8K7wQAeo&-OBtQ^PAg?{`xtBbp53{9@MlOYR~t z=Hli2{GbK;M%-mJ@Z!ekGK&K$4xvbpdK{&2R?`E(drF49{h}*cZE>4X(Id&Xy6Xs{ zFb#37{j)MAxy>W6+xCx|n6ux)F`*;O`n_{jVr?^iv8RXW(;Z2b0lG3(KyFmg-nIHJ zVc*vU#zuj~VHnq+{lFVj$WB-XdM>>`@m~Q~#HCArCmte~Zv884|6gB}L)QPcuU!E+ ziW0BCs-l(=bN?@NjJ-N;G;D>2y8qjX zqVr!~?LW!MpG1q1`)v4aH-ld_vlFtJ5T)7gqm|R`9n6B%rjRj<3-f<*qtRqw8*%5` zQfAFmT9S8{j6z0&9LOs}Z8zNQ@Cp8vH0ocE9gp18NONp3ru2iy>pk;P3PteweVvDM zHAlkvlQc3O-LV+@@p3MxQ$r^Fflg%1w!F9p?6GcvfnMCb40%EE`A4^b#p=$5u_yMS z@4MDDB<9x@<<)}e;x*Gd>t8y;2o8AD%AEjMhsBZf6!2oW?fDS;JiLN#-_y=EERY!s zQ&*FsZ(Y-o2Ha<9HO)9EPkRygHRnLpyuUwxXfjzBQv68e17d7?!Ms6Z3_Y}Hf?BMN8LwqJ@prR`9OsdqzpEDy7FW>;H*Ow>; zHU;DmjpuMz7Gtawv*Nq;y&PE)KAhmYECF{)Ij84DPe{~92OhbiGd81e4Ov#}k?2-_ zJH?u7Wa-B4SP*&S@%kwxz&<+4l<*n8Uo+}{%r(i(4D$GP{+8j}4b@oln62Hcpqc!?0ey!WA?RJJ_hKw=?!-iuB8&6=<8Suld)T#@`R=HY2V}E5S z=Ui^tMtr?N&|;T%=!^eM0gdy&MKKoRBI&g0rLchZvEg8H@(Lo z4XvVGhGQO?3bgS|j->%3ef7)m5dyG3| z^cUNS!$uqkp>iH(4j$`seg31cB-s*sDHU%V_{u%8w(=u$7MrS0o5^fl#+fOVE>nxJ zF(^uo5w0k5WY-~0*2_`@HtZUuTYKhD6S=Ajv49@f*9o&f$&+xdiFlwm=C}J85yDTtC4f(++<9sft0mKx;yUJmH5_(ijbDyIxl?Y&tmg@;IR) z=)LXZwcSDgQR4f{X#A>AH~zvx}y;Yn0dN2jh5*gC3PIfVt1JM{Ecm;A7P{VxJ6K}=Xp~bdTHo44Gto@oWpf*+JVxxO>P0ty$24eQ_a^8;GVI zF-)rX^n!4(%jZeay4g>Za390Jj&}&aRm+1C*r`uCaeGctlR;dWAr|I!`AQt0DCDbl zjm1t@R}C`Bw!JK98;Ak~yBUTk{9;Nv!5PtC%p8)U{+XCW+_Ay* z3E=Y<6}XlC9|9G4bE~PoQca33^3aDrV&+H7`XKrUbqd4QsusK69Z}j}?`(awS8+7+ zu@GFH<&s&uyH?`$=LGTna+8LDd0nLWpi*&0?Y<8YYK)Iqjx=y`=(CjT|79nm6Md4CS;*Rs|~6BtA_DeoUa z6xkG7)X&xE0XUXZIshpy@%pP95+Qcwi!)B;5!`bX;RnArZ!I65CSe@&l6wv#+ zkoBDBe7ltWyR*+EI5t>j3Dq+5tOP_={7(>Kevd zU8NHs^pcQ7VF2k;1B4I}A(8+Ak`P*wcRx6D&ik$JeCw?DtoNUfwU}8ENSCz9DxO zk`?itbJ4o;vW$n6)#E3Eeq{u1V0CL1VXa%)}zK@J4oyP_JlF6j{@2@{LRU z(&V{*a*+R>=2M(6MHP7Zv#h|srZ&hnqJ?01yvCco`YuK=CWFUUVuIlW_4Cdg%9%LP z(f+dS57R(d46vKNuru`QIX@#eJRq#>fRb|^@smr5*LY)T z-SGYjQ~~80SV^$(_n##@AAPu5ZB--X-lxHt*s7j(kfr7oRhV|Li63D^itTS&5U?hx ziO%Bq&gq=}QTB6~A#}6sqK)&(J-K*Y(Tchtg~pZNHwbTnvZB^q#+eM{*W!Z#T{DVo zqt0P3_poZ)uP)oehPjd1+3K!*sx+U^K@dwUWnB-8T3_5Ask~($R^nllWFwzB+x_;m ztjc#Cfx_&unagx;n7obeuOePR&b8%g%Yu;|ai zsVC+J}{ zs1pd#lf_MxD^a{_zB!hJb~kH%X7*&LYDMa8%gHJ>gru+RG}y@oMoAu~A|8O{h^Ye6 zHdq_@Skj1D7}w>b4)9qShMDL!`Zm~xQfFfDQd~XPc9m)4TW2M}A2Ms=tR5R&% zk-%ZqHZ~9gpkgRZdv(v5D&OrnLeC&=dGQ0CsM;Grl(L$w3jkpzD`BJQBPH1-L!OdG zg*P&D_OWSJ_ZK>XVbVLf^!*ppKf5DpSV^YTtrI{&%VY$nP?;xB&p9rp_0I9RZUgmm zGTpQ7Te+RyvT|A-V@W0|ePb)hNs?|I=3U^0!b??uJH;8P8)iumy66doAdRAHbJNdC z0?}*&GvEioPYrxehn^FQS_fD?{%?Anv6T*^NKgSX*1$L$ywGl|qMY z8R{|uE$c}k*|qBfT*s;ri{qMKu$*Oq;}-_EC{%>oi5Y%L5UDTq3Y7M2rv5%+` z)yHAfXGvtJWDqzB`joKDvSa{Vq)1_Qp7B-XY7Sa_*yr&ZIZEg6#psM>a0lN-&M|l>G{~=E>0G*|e7FuTD2%b0uz`RX`-C<$K`>URWx5Wr_Po;Ek=pfcr^u^01;pI9%G}z?1T<`j5k1Xh&b3Iq`QJ#D zSbi4ijI>J_VuBIqTS_cWi>KH1j(DEX?10UZU*tOYq|OF2H=Kh%96s{3vIgA^u&D=U z5j>Bho@0HH`bN(enXIrC&<;2!T=>%K=$v(8%NRs{TaPsSDLwqx>g5&P4$2%z7GJ;SHj|QLVk!Kc!Kqv?2Ce=~%HPJL z=YRgQE6bZdfBZ)T`fvYnxQw>XZrdr8dJJM4P?)%P5QXwj-~Q;7+xG>sYuEn=*!VAD z34}m)-Nb)*yx%tTJ7%c-2sCL^>xT27%04vXbmfE zKXL=U{OYKCdu;rPO!s=t{2qP8WSJDU1qy@oLE(_|H5u)d=33aMh*|3Ea5dv<)-l(vA`2L? zkAwI_X!k8s;>Hr@ML_S#=t%`^05(v3en6|k8IFKY2AL&QbCy?-Q(ei59Qg=5X#XHu zYVzUI(WaRJle%r|P?M_9)g=0+!NUq5g&`?xc70mjl$I)S+-AYhsAyr}WB9mx zH@kbGUOoUHo%8ULz@!^#7-gx2@FfJ|f77h)aRN+BH^!$-g{a!+Q#R>Rp>alx=;~I% z?sBB`vv-j5d&SeB0ejM$#=d!ol|c6?7x$F}m-rwJvWLM5VgC82onVMO`XYprL2i?3`MD_peg zk2EKwK{^5;M~4D&8hiRl5|J0Mel>R>_GEgD*lH-OtB4)`WrLP^OE3csn#Dpm+uJC~ zc1z&nQy;XGM}?@wL$&=2c(xOxw;2k$Q*-tBT>1{7_Q=)X&x4hJlHfByhH8ogEz`J1 za#(N{Gnk<%A6DL=A;-sK5q~XoW;nMkD*h2>xM*8ARXeX7#5tzJY`}%f1xL_W z#{s;sNy_(MoB)*ucZC_r7*dR#ZKg96hdj~YdVNarX&)_mGkOA}U?7xMgXik-t8+W8 z+Gpf35ItXPyva)3eNpN5H6B#J-5_ClOPr^i=JFnNOz$hCf8Rhf&p95;T5G8?iKl19 zk;*e5+UCigaB~J{pUpQ6cr|N|4Y`rG$qxD}H>^jCyI;87jBDGF1s}^f&RRIEF|&*d z8k`MJDdAjU9I5``AX{XVx9J{F1hHaS)PFtcM!K5LVcG~-?nX+tKfMakoh{v_e|=ot zZd`t#gC7~rIZ;m(2*ydw#-$Rw`_qY=U71Iq_?$F?y18Q|Lpq-84GW52K z7nmQ4#=-D=-9(%58e0ot;g`nWvrBRUJd1jX*?IkfX?}?T22mXUFFbRfFlHdHp1 zmfN74p(TzuXIW_4|G0mx%Uf2#@i)@^CuT56Hl7xp!%jnsCB9Wrqyx@GFZ$ut<=}vO zE%`~4tk1#jQwWkrQyT1BlS{giA6y)U54YJcI?Dt6&tSbNU1M{yY6b)QQh-lC4>Qhr zSP~F6xe)vB+U5;~#_10`L;J5rqq#8+oo1?EOjEb0EE<`sjAo~*OY9^WLKehLR*r9? zsHC5g=S22N1>=u}-+?JEr52sY+RBa6@zdh!gzK&aDd_MXNwk}3omJOe_5}h<C z%&Z}{xgcf$6qlqOOC%`X~U116h1DcKAV?A5{I3H7?kuVh{%=C zR0m@Yk%YPu5gCVh5ARNioxkY3Mryjk)LD&SWWjoM-0_N!3F0f6OZG6__BukZfwG_J z@cp7wQ4U_<%Uw|PJ1@d!O55D55y+M;7dkjKHbtI;ZJm%$OKMqoD4q zIzg-EQw^OhdCiPPMO9!n&(-^`|E}u;Ww9kRhE*|LR%pjBiP@_!h?R;QQ9HccUyVF>;_opth>7zz7``AGt zz#+Vp7Mv`JI1w5MNe&)jn$*0@u0@^{-h3m!#NMO(arKI>^lY2D-fKEcj~u!=)1QDF zlNMbFy^=Qd<-Kn`Hwq>vY9YeBT;R;d zP7iu`u-Wn>%0Oyp83QG-*8q|GdL(=?$SzmS2n*Ev=zrzUb2IS0?q2GIn==d$wFdWHKbDQ*JaQf3sJ{3@ua)F&nZ-M!TCUZNs7W9G<& zj;B*3C&Gz*L|1Hu5TUh^42xGUt_dkEfVZ28zrK7r_qE%097ng$0r1diy_p{5df5UZ zRzkSF54SdTVv9%)qVJ9FALrwxp}T_WlZc-Kumj++^+be(Cp*=_9Y`HtS+WdcthMb& zAUO6v^(oIf=pXTBa8v-gulMgvp^`fuPLv;HRz&BMOJ%=K6}j~8i`ITy*}7H)CnLPV zCVk0}8h~I7UjPII`vujp)IM2zW7YAvE{(KMH{$`@h(8!j|3&62^Om_VzQU#4BfUx} zZo-ooy7V!l98bES{qP<~qau1W6+iArk4usyP&{V98ysP@Ekd=zFB5D-yU&j~$3>=+ zIusmzUmk&R2KWte}siMI_JDQS=2s2`6iM=8TC-s}Ep@{bpQf9S;8XMV2M!+3fwyeS|a zvs|b`|D<7<6Yho~tcDqzm?TRclQuVMg@?)xgF7j6Rr`y4_wkiD>u_Bqh+U*%!#e*Q zn293&vC}Ns`3`SySnjfW&06H!PoVJ@-Xmp+lJQ+%9`=-EWvU0BCG)h!2&zq0k8lBww*&T>${$i;SRce?sj5 zx!ZwvrJ=>L;Iq^T7IaGBF)7dOzml?|x!m!4*&_#LAd%sy8=fSHp*`>RNEJ-$e0jVk zi0y2C59poDjaNs5vjEp-%IrZg?%nN7af+lKE4eijD#Q1=l? z7{VVlGlyL-7%6#8d}`iaIcJaQG_a43semz1{I9(qkZC_X$Q%u@oSTq#0cmUL)7zdZ zo$xUgbNs4J(!H5bo9@&7>^@P(;U17B>@HF}IA1%$CL?f8VWhlqFDCmy2gH0hk;)NZ zsdqak5VFWv-i$hWM~{2d_87``fKkTg^NU;yxZ)iiWSxZGZvoO@Y06P!cM$W>_TNj6 zG&4?edI01q<~NgS0CPNQ*rOj$BK&fD`4NDw$cFu;tFe^iSTiLN-wlYzT)+tliR(m6 zP}aKI)OE5(9VN2z6dKRjW~*_?&8dC`LfBvN;yNpjS(^*n&Aj=hc|BI2MxS5JaD}_B z-Vif;0Z*24k6*+uw!_v&!jmPbVPtjU6w^xJBD*w;!{Gw$ZNogdEu3 z^6A+ma+0~>wqkAqTyw?*f8EP?sFr7JU(%*vUpFhh`@6$HNR#I-`X~ncfojd>Ai|wp zz$vBK>?HIz77za?lE#0@GW`GV9}_dI$-8#V`T%0ny5a8vmj&k1I`km(-v5MX`9B&0 zx!t_V$XFJhk$ap+iyop+nJ~Bf)LcI6Xh)Hc$Dljbmg?VAcVwGK`uaOKjpC6RN19EV zIr8zXr*oz{g)f;|frb0)5`5ZCv$Ap`w-hUNAr-TQ2$HPJZRYou_+2}&N5nWmWb$71 z$y{3s@9dCgPY){+IAQ4}P_zjT$Zx3rJ;!4i*>BO4X_An)h&e$Pre@mu_h)ik)BM!@k&-YLr3fm# z_k0=tUZld%^z6p&TDwyTuHgoF_)3~~=#0G=E`%v*6elvm9IsLL$aU8AxXqz6JBNs# zXfbtJCk_}6Gs=GS$I6@rDjT8D=|L~Q5FH@7GgH6*1dzxT|2VaB=C&xe>jZs(j=OSG z3!oi{NnEsXJn6$&<3O5rR`4)BCKzI%BbGan_K`>hu%B~HR_I^4F?12&kpqu#mo?8! z8zq^TUHmuIIo#D|l2_>zNj$beEZHw@#9QXPNRDXO10;`=?r@C;Iv)D-vhn%iW?tVT z(2ii6fb$~T;4sa7(c0$YK7?2Pgd&ihktImA(NirC=msTB*xS0HlpR(K1*<=sZWm}b4=%aQ-IA6`!indA?%zKwt$y{G4Ke{&8fg)22&zp816rfGZ;WMA`#FE;^! z>xh=O4=Apvr3h_cA}mDoHwa^_Wwe%D_Qo?}4Q`TsTt z0z=?j^T3Rhq!AQ+;PwUM)q#IAR|nxX%>=AM*QkURemS&*O`6*#Fp$=^c4`0zm)wl* z%}|kh(gTS48<4#4GC@r5oRN~-T$vSk2=YM$;aJ7TmHj+j#mTVCPZM}*MLc?6^UBow z1HIo{r-RB`z||SVIP_aqc7qe4=ReGQb7P!ouN_N>h0*jn7|ojP`q)DI*giFP8rgpj_(k1g76r<0M(1^y0_}y;OD;3YyYhNF7%!qG)8P`~0|^}vHO&il zK^}1aE}kCLf|`<&2+$+6N*x+_b-8)Aqh|KN;@7Hs+r^4CdceKrCHkg!^%4q2FHl z9N4w%U{k}^k*=SRQ)wpV>pqZ1v+v09oPYdrJ+M7`5*bItu~KgBragFRCzp#+5M4f@ z%uoB>+%@;)>GrSdCjOaJCr|Fyk~X~8EB$wcW7Y)n}xW`S<=@JH4;ap0MffS+M2me;NiL#a}L} ze&T-l_RK}>?(c;CZT}~Yat|Q)CVQg3gr@er9=tjGKhpgFvk>gmm>zQ=MfCv&Hw|jO z04Ia~q+0H%*8gljBXLg{#X~pz?}rtGfB8~Av+- zBFqxy;>Pb4YUldi@BSLtC0G6QkVG=@v@lUcL<8dz-yw z6JScXXN_JXMI&s{O9_8(PjoQt$#ebDLHP_`Aw5&wF9k5-Ru=!;hs*(2k8x=Tk4>t` z0!~RTjjrz9;C&{H*`1n}W;4J2_oW^NGI}pir@(KHnyB~tI|i^&Xhtp=d(iFQ#}mB&UWjHo|ndL3Y*+ zRX0UIgE6(W&Mfu+o)sU-{2N?Ex(-&w(}gS#T=3T9t}9fK8G^nO4!eXbA^QU0wr2q^ zR7_J7lG#J}EyGcqcI$78%dVUHPa1o|fz$5M&FVjZLAle_3@-zD$^V9CyNXXi9!Q}h zAnXmHwB#waQ8Zj?p9gFp#*~*LnUV20x!lNEot6|;x2HGx4FHmkYIg_`w;ZQ*jD)yb zUpRlYcm?t!v6W2f5|N3BUa4#3HrY>(Zux9aQb54He+P_{La!lL)1rW;EN~{iDRn$2 zQ{&Ow2O)fUt=yc1eUZSa@^{3vE&S#F`zA10uXf}qngVoCL$?vlcV`w_lPyxu%FFjc zyz|DZM97t_yh-}Wn*8@t)W7nlN$PLFDFW=67XRG;rGb_IiEq@Rrc`v-?P*rqtD_JT za$GG4k^*yPkzR>FZj_Zr`Z|o1%MTmGiRCr`iM!5c#5gw8)|?9uEybL9{>ir0pujVi zH_i!n%=hROu_g=1v7p~Y$Hw)2yf9-?;}HiG4`nuO*sOIQd$9J_V>yEF3()wZN=Z&- zhk5Xa@U@Nez-p}RQ`YRH<{TbZhMPE0;(~LqZm7R5q7`))fBb?PR9b6mRZK-xufOn! zgUWiTzaRb^XNB6d!SjU1hR`$$Y1Vgud3w#yw)9CKpr6~)e-?h^dT*}BzKJ_cWwt=D zhB3rQ*4~^H-Iy`UbnnkrL%mxP@|TEQ3suVQeI5J^g*jvQ4VVPeJmL6k7e++Z$yP%o z!at5SQgfGHFc>yFThlAGIOsh;cd)p-jnw#4@+xG7FwQ;F9gzUhsfz3Q4d+ggQXa3szS$LzL+y8Z>VN)9H$6B5&=-AK$%rmQP zpAyqGf^EbfZq|V(y>+kwl()~doYyD0>)j={^56;=OM}zAMl0j!w2_oez}-tg7C!^_wGgQ=;cDl3nLBy@ossXEyz6u6D33{4VesHXpA| z=-N*4>~z<^c4tK|MryE^af6L_xWL#ZB(i5;WVUQTv>dSZTYcNMukrK*5vBYMH4R%W z&>fGeS<`rk7K?ex`~a+tgPh0aL(K9cLjmup>CO(C{lU^^IZ47(-;mIE`(e6g@*1k3 z72}h?DAQfA`DOd+7vW7FpP<7YbhNK`uki(5#eu_QMHq|LI+)V4PgjUYm-3IZ;b6*5(PnYZ`v@?PH=bx>4a54IxWf??hobJaf zfc3-s;v;=S#wdYEF@e4TR179J8TP~q2gDUNf88z;%>v?qf>gs@}tLJ)g0MmhzP~G+X zASLgB9`{RTR;YEuq0JyW46nel)OPFSM={n&rK=O8C}GJgiRv1SR&sDIF0XD;(%^jK zLiqp?TYi1`&7}x-Z?Pl=*S$;u$Bvv9?qsTSTGoIfeud(zlGk8*8 zok|0S4_!ud(s)5ZiA%XdJ*hTQL6i4LuI}ED6Pwb(G~-{k#{CL1kbXSKKnFxM@7_qd zmluZWV_%5jcT7db8rl~`p5XW1lfp?$zPfoOpEFf;a_rT=W!}9ts(RZpFq=Im(9%?5)u6 zR{vEhDAtv6{VQ*k;+Lw>?@^PgRK75+swh=8a1>L^{-qqLhF*_{>3H_{Dq>WodG|9LWU}8EZ!9q|0Tck$Yh1k3OhABv&dF= zJ3*izC!{BUq-_>=H;=XXGN6v}>6W^|^HV}7Q&%~M60O__6OJASzqH-q2;WXMul3{n z5FQ(L>qi!6q*!#znhvW+s+6HlauJyGGQXA_bJ?t1zPgWP^@f0+TK}q5klptQ_l%fo zZ(w!rzG;jts*GG~^6aq!vSB>mRefoA#j=P!{NxTWv86{uHlGpXjY&$Yn}hx1Mk$PD zdt281qRxP*LYA_9(t%@5d(huXd&*A8JJ*b4_d*E$kwYxBub%2{+rg8)TPwEi9`(WYKN}6 zL3p4Y!7rh?`Q;{OW+tS!AX|3CM_K07wY*r?5V^s*NSMN}-j~<>Q1xYrC5@G4DssQQ zIkyhxnKYHj#AT>FPwYgo_Nl9;u(TWprK0G^MVTtuv&giZq9)tJ;t24ksk;?~i( zUEPWgBt=Y)iT_gky7)oN-u>AfAGQ0V!5;QtxI*+fVc=XMsf~x3z^kmhu>qGo!_J>m zbS$zK4f}Yv&g-+Fa~Ej0kSmEK8GUYB-jRN^6WYx-N z&m8XBuI4(aVV#pH+g6BVOTptpWk?C!Rh(9x6~j#4=hURb%nTa&>(;=f$M8h>y~&>= zStI7))SUuhagh=b4x4wU59lmMGw7IZ3=Pw*iM+o3&V$?R@j{JpBdPOi!3A};Ek~d? zgmn$0yZ&YWqF#uVrKkL-;i9FaTyz8WYB_EprvC>&Qd#0Y4x=RTF?tw(wPYgvTXB5O zbz*vtZ+2%-VrO^pn@f5z`}WF6X*vZ~-Kr)P>XRygTqOUyB;0bB8mMptB`#0 zThJK+O!M61l?S9S22wI+-+r(ix?XKCO5oYbAhof{|*(na5)bNm-GgiOAO9E#B?mXTQudAcT5WSnG{pFO}!ar3r* z##S_t9#XCi;tF(ZffS_^$hjH0#f*lw6VeIh`#nE&(B__9Wll54X3`~`{ie?CS|0+7$F65-0wvDk*3UT9$W2!y1j4UD^W8fj%KkKZwgn*TLzio4oHdt>I z)1{nwL-=cg&Sc5A*z2S)iBI+9{a+dMyt$PsO#U66wl;%v7eBcgLD!h3 zw>JMGMmBVN*vn93;OL=o$72(9_nq!K)HK@lx?(EEaQA3sdud}bE3O!To zbk)(9bag$%bkZv>MZ4lQSJXl9xJeK7hksKD49zujsPx63BaioR+3V!1bskKKO)s{GP9)`gn}Ol4 zj(Au^Bs4dRre-4zCZn_}TaV)4%tH9Xg*boj4{aa(kpkix3P!XkJgf>fee$yRQOc#v zaH)B)xW0jJtKyzCq{=5{4rOlD&ZlN>g)K(>&8Vxdcc_q(TszOnKY+ZW1e>4e#tvKk zDO?AVg1+HX+P7zX@}3T|=B2~*kwmfr7t~zLJ445gW&-X!Zp<@feP8ItovVB6{KSh= z@}vcS`HD`U%HN``s2ExJhCG3X`t#o~tx z%KVz)#9{e_5C7JI^_PRB?4~+9p!JpBT3J22!eI`4M!`S!6CKSbBVVjZXqNU1mwh@t z^Ykn}<&J(r&JAJ_h5HVSiq1uk%1yQ}x@=+6!uYA|@k2=o4da~=t+1DKU+PvkIFVsA z)*oNku+5E-!9`((0^whl-cD>#KZyJ(kTi_7MBQZ^meE!(vq1^TIokUEI2+ub;c^J) zddDE|^5q}!8LJIqs^WF zgk_`Pb;PB}bMcZ;-&>sRR>}-r;2}w)GQ4hda5LH_zXOurRn4zc!>$A zu&b+Y1e+^A7}>fX`e}iJsMyicv2Q<`M)3Bq=O>M2M;V{~y7jm(_%Gq2#wxHZjcDc_wrQi#-B zcit})%D~@ z65YJu{ub|E8a(dtP}Dbk(naze%$o@qtcW}ZcWV!?9$%!9>grCl{y`p2qBYU$eNwWM zQHM$V6sxhT8?#=n^tV;&T@+3wz&w-cOC#m!%s)CN~w8Z7!$vK)%5>Iq+m=Ab+w^klI| zU=^qe&n6mP+Tt|t9AI%$(FqN!@%l;f6{nliX)P z#l@7#K`TmF5vt5GBpkm|@|+^!(teBhCJmAPS70RTduN6v)y*@*q|Rwcn_El=2PFVl zu@o6w8$k{O$nLZeoELEVSIV1;47KOCh8lm1`PW{s?MHM{uRqdi>@oX_=@Q_vAN1 zYjihh(h$aqhw<>b@cWZ-N}0{Z&f%+j8oE7XPZ*5eKmYN5zVvEnElB-P0G7_w6XwC9JUC1`> zzxjxO1}i5u6Nxscx;0VnLy(+b9LHIN)B^G)Z2Sj5obH&N@w3?yiVN+o!)32cX<}oi z!R`b>x>w3mM*~QCPf+k;`LH%_P z+X9rFM(sHQ1Q$k+%f}ii)O;Zd;l-^dZ+dh(kRwb3dUb{+n(j zeH(cmFE_5Wvq6N@GpNH=03dV!86)YzzWdXP^txpv*!i-gz@IR!r2llUtfrEcYZSqO zf*$*KW_e|iA>c|*U3mI(d*-*9QeJi4$NA0A8oMk zSy~0Tv>Q`504RVaEvwJX%vB}hBna+k#}qz0S2=7gnzUqChJ%@YauqmZAO^1#0%h%In{Q({H$7)K@USbgHNH z-&fIeAzYZz0zHzIy3>HE>CD~9-%>s8xg@g=pJ+Xaxa*Bq098P3|8pk~+}Ozj?qm5# zve+LT7qb(s-$}oaK7)9j<`l#GAHm#k`hiRs_7Blp9)~`BR87WH~w^a7*GMO z_hy2Cd`Pf7tUVVwP>eW+wtTU^nZaFD>Ih!%t6v~Ej-WjeZKH7yu0E+V0qq6|=4@Ra z{FyjmONboSS^)PM-5rU)-Bdv%-^%k}kk-_mxjPJkK9a+XhAIxoGhoGox>z|lI~nAc z3lJcc_DRVloE%m@#r3`Q3|75v|ku@)Nj1pL}d8Pvn?dx zcr+sxQov(>TOJs@KsWzD)otSiKzq-B{OQ0at^O(0PpxR%n#Qra%;)f^ zf}HEYHx7bXA4A6J1+5-9X$2N3A}dkpU>!Ms?eTvhmwKRG!y z15$<6a`p5`joS;EatTNED+%!gBU|NPH(^J)vzunjk63MRjFhg^vU5_ji?|gvPAmD32 z9(2;1Xgdm1tLZd}#MatS6v|U0)*GXo>WolPq_>|h=>f2Jmhk@FQ#S2ehKUx+9BI>r z*It|~e5Tppb?U`Pp&xe52g)v_HNDiJh5QV)QfJ&93qPeeGWT$`G<^)-meVEW9FGr6jV0ih*!YsQGoW6*=0us0Yn3D zC3sBiZQ2TZq&!ktwZauCak=p_e@bk)(j~vJmwRiuXQr=Mze-AaH#Ro5DqQwvS-jQRMrc=- zdC_QJn7#epy?Yg8Q4kZ85~f+RDl3w&IeqdB9F`T}5j@`CsU<;D2R$toJcPq+XQzgo zw=U0AD_h2Z)_Ct;p^eRlSQRNx(zVr>GZj)zTdyzX0@k9Qq4}m>{>#1Q_sZtNTY-qT z*qeRW-7l;GJ-Mouc~31}`_!H8D!!gtrnAzwKL|P2!y6X^;!kK5s2$Ig>I*X)%9v6v&Lj|@2|J=N3;14O#-4ZH;a_3PcVHnc{K^hTM76=K4L4lAU~&U zK+|VpV}iP*Er3Fx*-z-{*aU7V=9Qk|!&Nn%t$>A@0GcacA-{F9?shx<*@sv7RU(8Ek7>?kdQRlOZyl!T+car6b|lX5x4x|0 zr5y1LIB0G)!VTWJlOn)v12)eRFe@n`XRQIghuAYP9rX9pZr(z|mTsZg!9Lu6)zG=! zafHxEV6BxZr`tO;`aag>`Zq0^HZL`|-Kqs!3Lj*(cE!QN`%dZb8;(-Tc?VOm39YnA zA9AD)GsR6JXJ#Q-Qd!pUg{}XvR<6Qe&5=o$yS$jcKz$l@-m+GdnY`fF4Ni_)T@7;E z@qOG>l??phP1<>pL(k)X9O)&p(j+6ft==Gy{M*P_E4w6I*D>GOC>CPl#6`61Kmcc~ zM@!t_Jb2_|2dQj(_ltI&l|mPO$3yZ~4>n$r0SJ`0wt75+aSa%TIf@!-GEG+MKD5j% zx9R~58Eb7J##r;=wZN(Y2nLS)bR^J$F)qZbb^%c88}F$4N8g}+WU#eY>l%5#irZAb zCj69XXvjnWs0XRy)1@X-nOph1hCZ)r2pGUeciIy_}lCUQ{v~ zEEYvuG5X3Ut98I?Y}eDUb_-ZSr&HvT0c$ufbnNe=Q0V1N5`CF$3rB4vr{F7|V) zeRt*P+6sQrDQ#fz0bMXpmxv0z0gm?S+`!BExd19mJZCj=3gQ394HpCGvl0la&s^XS zQ@+p)yS;1XbBZVf-3e1CQN1=a)xz4f{QR6@dTs=&R@ok!EfmgGrt4VzRZq^ua~G1i z=e^XX1RrDl_{h8uZv^QLK6C2b_g0m>|N1ODg0(a$@&iwahOCdB!zo4P3@TTv(AuLm zm%Am{D=9{RBh=vqU$ducp@znrrsI8F^!M&tpWp1pdh-TDew>pF>Ag6_2mPT zQ(}|{2i&%COzgi(qR7{|JnChm7+eShqaI$rSyeqJXIJqgip+lhQIs{lJ!{roR@OhK zXbU#7V=dJj8!k0!y*rDv4oFnZFtdfwu6a`Uh<*Vfc$AX+b|EV9r5@fBfDjmazCM z@B-9{{Q?q1tz?EZpt{-P+pfmWYfchT8_7!&7j7ySZiAh+zZHOB4(&mG3-g=0Xage1 zC<%azQrixpiSV=5Ngic80xC+($pw4Pjfmn2O4^GTwK*=113uWANGD5~kOk5FudULoIm>Ww)~l$^hz|!k z%Bt@wFvMB&;e=w(jx;!Z9$V+hzcVXrccN3roPXlh=%yJxB*_2aYNVX3v@J!>-my#_ zkw{x`3$Gks1pN8v)YlfD*0;mQ4hXC&*1xQYyfseuJ?cpfHO<{|etARu!p(zw*SEkU zVf`ynTRHb2jtG=zItaS^Lky#&{64>o`y^M_xd1>TXOqB|@@3>Li(!B=>ij2e@}nYr zo7`>Mfw+lTs#aKKvPVZEwP*?XS7%3M1*Ni%fW)R1fHN@2dppR+SXfUicY$Lfsz%O$ z)_=GtSXN96hH+rq`KbXAc0+eitS$?Xkiz(=WFw==%WF7Sx0?;w5VI?r=M1dm~sSwCXn7UY;q)_ z^d{Hy1xlj)n3t#3?JC;GDwVo`qv+NSv(CG9^M92LJx57c&xOgzdW0_w4IQ^X@Y8|f zWso^S!o;;m5`+Bs>=kpf5x`i75G#FTtSV|E?MItkvK_oZBN$yreYDA0`gUErf`oCz zX$q~?hJ?jwH0WSC1@|xIws0rVw%7v!{j}BEndM1@pFVogx@o_aEl3eSS$=}TbW@0i z&LmaYFmjMkO%0t4C^i}e`xr2}A>>)-=Ofhl+|ykSgl5fdO?B->U7HXw%wm8dojMk)-G+;Td< zp26abO#@46W)kz??9%JlD*cQ4e5QA#3*mBGf6WNC2!>j_sHcUg`JQ5{;dv&(*s=cO zX+Sip>y?irqx&rEuD>xjGG7ElgyNfA{pObjs?VPd29P*sPpMo7-1X77mnRyz=Bh8B z1x?UP%U+YK%v-PQ4wcclI*|BQ&|%8{tHtwJZ3it7s`T{z2KnoQMzKP6;E|;VeOtfRpve6L1X{tM_+U%y_1T>VyRO;vT#3i zm(ClE417V@8HIbQTP98ngr93h;tk0%F$wF29Skr7g7m`k9JaSa90QW4HOk+-(dV+@PK1Yrr{u!J%g3$YFe` zVN6=MkQi&0XgG~ zsljm?Sg_-wF5vsEAG{$9DtGAy`1~RL|C}hqLN2QG!q&$6SwNLu{vqm2jwKCDPaii> z|DRf0!npt>iRz%$lq9%CRp@CM9KI%U!3?DE`va?opFcaGc%gqBU)&XH6BHFc%z{BU z{>|E5U?nWp2Xfr~sRRO~j*NWf>4*)H>h72A?H-i{GXwcB_&9Epn@iCs^8VBjLa7^S z-J)A=vn7H$^>~wXa7fn5L%+^z^f~~aR$vYRth-#EsVdjtVgx>w_&T#fa6P&^2u=jm0}x+sLXf+yvs6r&0}jF{uumhZkVt z3>I5o-wf@64akr4zAk_$R0WVM)X#SP#&E@A1`V4_1a@?xcz2oLxF(>xa<}P1vvadP z^BLtM{=x1KTLSGyarN(rYZ;nhStScq(G{ibCn*1R0F2K&Q0?V6-6N}DIXsPbW$f&c z`Gv{luUmFVHB%P%`Qa|bN-Mat=hj&EglfVNr(3-k9KL&osxdBXjqB6YGW6cmhUV-h zVgLwz-oL*)xht}{7pQ`JbRzkF5S4m?U;jIjhSQ+XD~hHpuHCO}KP>k7H4&@_+&T{l z-(GSwmfr%uG7q#3S!qSrnE)K-ihG)%YvQ{ph1Pv*Bg5$jS=`kI2=s&2qhb>N;>o`K zv^gI*-F1kcN0pLF+gLEN4RjZMD(zGejaRk>VJo7?^6vb%&gN=I#s+$SXosoo{0Cv( zVSt$BTnNcv0XDc$Y=@}4vqmC04`P6Q#l1mzZBq;3Xf^jx%e7BODt|TBF0GVU0oh2V z$HN6rd_xNBeNfczvFs2n9(C5#?E@Kbbx0MlPf9?&vQ3sql)?{_Ao&+Ma5?rct2%+9T^ zw)yuesNrAkkhCLXcEne0lZJ7UzTC}6dV5(dlaTfIY=ZKT0!@|>0ej_C z;xn^tMi4yq*TdD1r}b32p|4`zoDQi?#QQ&OkhLAWmIu2g@Blxi<9?rN-Zi(&^?)*% zt9o|1V>|Yqky(A3ga=~7pzf;5im5Ugp^zYppe(Kqo#wPwH3T0hO#qaLV~5)MU!^+1 zVXZc4K zn{`<`j0{0+#1u_^N?ioKFch+3bK2$GW9@KU*TLT`Z3fHQChU=#(_X@OL;moOnqq4a{TL z97SvAWcR8OG2(`E7~PkU-ah?FS7eqO+Q^r;C9*TI%1DBZpA~#l(>QEDuSVK^+qq@P zZ_8SBs*d{RuXa8|tD6EAzl3W3s;ohXG!SY7utfa*Bly4NOZY!sb`hUph#>Og{~Q8n z{}tP@|Kh*pi-r!a;Ckx=rsehTawaALNG`s*zjO8!o%CwAt+OegtZJci!*FH~U)$ra zdHc_J{dJGOh5vwz3fb=Q#@Oz&e;(=+gpQiJV~!#kk*WU3qtF!i&-2`a8~szxjri!l z>4E+q4PgLChVVFA?tF0d|M&jEIN|<1v44N`|HteNQq$1X@}mGG1>nQ|m%C+EBunau zk@UM)v%ilFN;m&L6iE?2<-f=O%PiO@2j`7ZG2J>RdshOo;GMr;g8(^bny7m4bM)RU zN@}mMvZ7)*YwZfw$;Oz(qeqVbEzm*5sYqjd{weY68s5mrEV+a%Kw(>;GWzHHt0CLQWs_h2_?3&l-dS9uC4f(YV~_tg%!6at6me*7oZEXAv8oG;nu*6rla$UD&c zBl8)417L?D&|{l(_0?EdSe!;(Po{QGAH(+;wW~gi=(^5j3VL1UxbDp(_(rf|eSO2) zppL6K*9D7?fai!Wu{Itn&$-N4Ujj}jxErVAKT3#EZN9s$&uE)(GwOyqHwe03MdNGO z*c8<{ZKQoherUPSh7!IK*V59uT!~U38N(nG$N_+_ zjg{W0AFs@y2-M^1>Z(PX-=pbT$LzMYw()EQau(e>RW~=c&c1=6A^4EcT>%(2MrP&$ z(Ikj^-R3{F006A_$?sKhlb9pj`;FAIHU`5+WeOrppZLY^|tpwuI0RPDa zFjj<59?bdN-9U}4#Fmo)LM+*1mlr|UM8{_xcU|zxrj`3)-WSdAgV!+&aAt!~YUTh( zRPcJgow3{Gbpnml#>R&GK_|ZRg4dbF!BQszU=_=(mByfwRb%{@Wk-w=t3V}3Ad?g* zDgy^-Y@74o8A%R+llHN*fu^|NX&Sy^kQenv(J?VG$z;nXDFY%SRYXKeO7UX5|JHb} zN~e1n8K09RHl6(V`N4AV2`y8htVS1|)X{HMkZD@?{*V0T!7~WAd;@R0PhwAg~BFFjZ8{4IXzCdr8}?s*_wOca19_-#Uk(C z;Sv$$dF(Z6L>~X*UZ@dZWn*KL`ufHJ8yg#3j|mk8#T>{^WQOw=OwHVCs!frey`}p>i z+2D9M#XFr?$@{fVAVNq zj@!!yL!q(MnHd@5k~(73)wX*db)6P?9oJ+tH~;Fs0Yq$^jMnv`ogfMd3Ozsn%z-x` zrMcgnz*o1n@_`C(2GS*mtDeiYvuIc4041L;Gm!~gCzk#?iHNSgs@)l6@NNOLSI}W2f z$(sr1rH)5ZU*T1ht*xz{Yf`wuaLdX~ARgmOox#q3hAB);P5TT>C6xos)ttbq@)gb z*q&ZqGO}#>KzCe=fE6|eHlEM(+%9lkD|WTCn{2GX?dbS?IgCj_Kqp-y%;h))*=~{V z#@9xeXaDModCGxHXN-F#ZkXG8h8a=%$3>V+Uomv+lyYV(3^G_uzeBmKp=*)010R> zyEmNrWo;;>7@)=xH-xZfAU>8)IzEBx=R2+sX2wo6xH%Srx7+w#cgH&dv6)nXzM?;Q zq6#R30M0}!&d$zWrpbJ{mSBrRK#(&&uA1#Ec+i1;2~J>A3Be^LWl8v@Zj*RVKpUVZ z1#ga30C{<{YR1M^Zq~@y{=rkD}Z^CW^72-pq&R;OQ}2JQ_V>4%MH5j zEk}|EV*%)0y$96@*Mwpg?Kk@samr4pTd;xGVaXM$@o z@$hKcHeHyODj|u75@oiuyafX4AuTTt1GmX((uad^T144qZf~yof#qgvI!^=2G|}wi zlYN2#c<}HHHRNHFE%ga~(yIuN|^Fe)i zk!VcxU%Szo8o1ejybXww^#ua=c*rf6rq!k~WUg;+02DMESP`A-S%+X>UtekFa@Re* zMli(FHTLNaj*b&02JZkgx?w!IYDnNH1dmlG2jS@)uJmTYnhn|?bXNevDMDGKrKOcs zRigojq#%MyqOZR{U-|^}dn->O?FLf9<-Dm1(6R3#5lC;KWnPw`scETmU+~%fV*BN~ z&|NODoPFKh5(seS7YxCiyX$qKORxkRa}re=c0NYv!QCai+39da3ZN_z9z>>1N>GQ| zwEJMzKOU+;RQ^#0a8g@3Yh3=ZdUp2q&dC+(&;F~kjnDXhv&sCAFL&?%ba(oH`$hIz z{!fShi5~v_BOY5sQ1|aa*0Jod)CJ}b5n;<#ooPs&DXK;c zp-}Hz?t#k=v+n?h@rQt08KBnZBK(@}Fmg8MxpI%=|KdWP%-A*~fDD0wfqlPz#ZV(0 z?(_XcX$1u~^{(m#@BGwv{s`nZN5U_FbRGUPlFnt&=I5|n3MnLd<6eP?kr0Lo&?*pQ z)mTrDtbX0wL50P=6=j8#D0o*3P;h(9{@jj>ECAv4M|GZ9P@i zspP8UwcHgt2B@+m&M{SQf-*8QH!jvw;6Q=602mfv)_JG+{~5D;_oP+wqiR4P0IZP;owL+S^YRV*TisIfN!*jYJH|Iqym zSPUjk&WcHQz|`KHuC%H(iNgzvi;Dx60T8mi8!y%ph=jZw1TX(kA!bq~TmCQXEtpuT zNDyQS3x7V{TPOwwQUPFJwZ2ZDj7X3(fG0*cp&}x_z*}6);isdMxH{W|gW2G6+18ZM z&9n}q{9nCPJnjE#JbwsX9X8nnfF#|4~ugjj(lh@)@LW|!lu!6KvUb8`Y5>aj|= zUOteSSnYY>Lm;5&l{Ryb;^x~r>RgYrT>y=UqDHv=oAZqxfhP#${cgE!Ql}A!JI#k* z0E&1n;D+}N4#I#BOR}es$fHzHU{&0x?(OYece$BgX*QJXFmtk*Uz`UX8O;6WOm#7o zlz%PWtP%p8=HJR&jMg5KqgB>3f1U60(h^|Hq5sC>AQ8SKyZh`XEsw{p6<7*l2XJTf?^z!8}I}1RbgPWUfa4QE(87?8A zmSLmmuOAj5uptuoSR%8`&<`9u91xro6fj?0UB%U36WcbVKBp4Tk%?pFAb3K=>tOtK zlL3r~vZQ2yp2rRs7-2OA@Bb;S_y$~#)B?m(DHV!ZlioiP^DO}QCgRcff=LBXdK>YsPws$F)FUK4IsNxxtiGsmjM{QBZD9^4~ix`u(k zx8~cyhhK!tX3)uQvSS_D+b<)|#%5x+N>3@E zIX`bo_{66YZWs{;Ztshddc7Q8@JX@tdnK@+5sQ@nK|NpAv>ep2uP!gMfRaBwAM2sC zsu`2GIa4-g4+82b%LdV;N*Udzh953l<{x{lhGLJKamlu^I z0aVlf;^?8ZB`2QRyN&;+v^|8?_ikm_m z91ej?vbwcicuzoV^kB?P?Lh_1#{@#}^1`6qXtr>La_zD*jlm1I9 zy^MD<$EzWFdTM2Z2xk+{+hS`sRNlVo74@_SU$$Kmpyd1+LavAkje@!pL*Sq5@U%gN z4_{yO&8( zn3x(f((|ZNEGpqP;p5?~Y<=t#bi2CjF@CLaNoH9NiHWg?O!4vtg;@R^4#>euL53IU z6-_Y3GA^#oOk`Lro|PtrQ|!plQ(Az>p5O=;E-U^f}};mtPZIhcz;W;N<^gH z(q}|)llI#TlHzaI;+NJj7PF{A$ni8JO~>BIIPhv zoMuXQ;fhzr#x=jP8l;52ClgY$n?Izkc!7gf@--raE0SQ5E|t#jH|iqVhue~NZ%l8O z7Z2}x-l8l%gn1whNxs<9GQY1iiT4^y5{Zi15Azi)#B{4MKY!DvHra8WoNljBTgFwx zRbxms{|I|zLhZ~nd7y#Yc0Ov|qiG>!^uBbi*^c)%tczm59W@3wTHL{uz>y+UlbES1 zGmF!kSq?1=zS+A_!Y;^jbyj6!T2T*V#EXW{{541t#7+s)!b6`>QAS;wI_*V{w4+qm$H1M)lj`K$S}NE5<6 zw;_+Lu;%Mkw)J-M+m}LTjzZPT?!fg}U-#Z!KmYwusHgeL^$x0@-x;iby(AaW4lfgm zTRNSwT{rVyGy8Mmem&-MsZd;VJ+pA@ay!v{sZjx8nLkQCd*Szc-RE}QZNK#)Tm5{d zURZVGj`j6r@g3iu_gTG`p5EFV_<@UD=H0vY2a9bJ7{`Jt^fVjJ{Hibv^Jm|T4$BPf zi)2XrH5QViE3_XKQfCz~K4@pRvU&%*WZ2=MmJ(Uw5oP*1^Hq^O81}f(OQLj4N^%J; zF}>i4m{R0AYI`feIthd+Lsj%MZHOn`tKlGZ636plEGe9ONL$QZnrwn=sOcl|6BCbh zgFkE1TF_qKMNFT z)>jV5ZDGk2=?nZgfU8fnP6Czkw_1PJpYb%4TH2aCu?i;Fsk%-QbC71Crf%%kWyjgY zr(L~xhQBy0BG0b~c__(HGWZ1F@`va=8pv@ zS=e;$Co*%kyeLr~cv=CY`oyQV42h09I^@5Zd5i*=!e0*i3BT2BHhap=7Ik%Rouuph zXiRf!NNdYyDA@PpHh@0pc^f+sv^N-ufd<0RM*nlnX2hZs<+Hf7{jVrhm-?|mzMxSB zB8L7Tfnxgp$95g|9oIV9fZzreP^^y!fk-xdi-3MiG#8QkzpyVyVgE6TWLyR^Y8!OX; z6ze2aj1h($si?m6Y45^>eNaEuc78D@y|-W6e8ZD+d+75v->&XY9b3;-pRMjLm&YU@F z^FX>OHPwI(jAu7R`XXQ9Ac;XmW8##&Iq7J!_WKI&=b0yJUffzngim2oW6{VD!`Q2x z&={(V?;5W3dh~BQQ;sr)?kIudLKkENUYrW%Zd|>8d$i{hk}hGpejey?ucth^oUU1F z3a#epQ*K;p1^Tqz3N(T>jd}?b2=@`=yTL%Idfkx4~|q zTYECMl?c+UMZvL#RTkUY4=lgGeftJDa!oFU`T~_^)^ljIMc;ezSNk?U39y;dJeQGi zgukh=2%-4(__Cc{O)c2XKoU!WI?#2<#4S)g@*yL{;b07^02R+zQ9?i=J=H%W!?f@KybBA$6HeKcxFTCv6~7 zn)zOmnwVb6Yl6}So^`R$eM|dLD{VF6=9$X_%Qe?6eYVd+5Bo;ZwYngQn4-d;aC{5s zc`F1I5o-zcA?A^1ad2Ww0uQ^hMH$n@q|Uzyh-N{Tu=P-b$Bi~(I470V8gSy zaYDKX-IRR4q|paN1yDW2PZ=5aoeR$<)QYv=ui_7kVu}--3UY)-DG2z&f_S7}`9C+mw5r(?cF!x5f#!(A}=v%8SjakGE>RQ-|J1QM!Kqi`6;7a}Qsk0h_zE4=>gW!pJviJ=#fR0@lX!{J(}?|kp)j977Q#d?g<^A-3l5IEGANsp0z%LB+aX~oIIOF zZTsjWHvq0NNod8A&bMl2v-rCRp5K=k<4BjAm&jw2x+&;6rs176C7`}Ua(whDhSS)& zKue11TWung`%}(bi6P?$o6BbLfoqm3LGGKv>x$K?N1Km=jp{ZG4p{KN~*F_YiD^+HB#`;^(qyYM+G(oV&A z&}HP~=7TS}+E@)OtBLt@enrqSzchLVbx`RPxyW;5Xlqgei!ehq@Cs38*z3Z@d_cs2 zG6-R`+Nf%rQIwLZp6P-OZkBQ2xJmIzYwck?mu!3a0{X5^5!=#h?)k!RGyG@WgrC*@ z4D42Mi?E7ak_t4Uk1E<98hsuI+=C2UV73t z(c#9D*|n(n7-@BG&Vb-&rHItma3m|ze5-fUQj$uSy+jZzK6}x6QY=)Zo$1;7XV=v3 z&Xn}JtYo}Tkf)RUB;n7zX3>;ilu|ySo^uI)c{npUZBt#&UP9~F zF@QpMfV}IlNXcm?z{VY&=TqG%RW!G%;V#SY~g$ zK=y<4Sak9FJ3nBkmY{wh{5BhIGEQ!{I3V?G-lcn77#-8!dVW7?&)}ub>RI#Qo!v~^ zBfYCx?&p63Do-4*!z6^dWT4Hldo`f>%9+o#PZjMpBQ=D`=r~ftI}Jac4x7+tni1GoH~tDrTiRzSc}pRJ+1+H-|OrJxA63CXj~b;Az%VY=;w{q5MEKu@;Ng~xTv)`BEScg3{hJ!ii|Zf-GpaFJ~v+8h0FCwKIE zy&*{Zbe~oTgN3WRoc@KDfrskhhQYvvQinSuVGNN`$G6}rm)1e(g^rr)A)b<}hiX}U zUCv6O{QUPSgZhisy}RS#8>1qq^!(^O58e9zD53^#1 zC6d}S+VuE}>Op%nb>M~z))IY9R;%+~%L&(udQvt`^%#Rjp$vLy)`Ef&43RXR7tfH> z=wCeHgkPz#SW=i%mbhs^^B<0}XsJi8qJB~8>#V$Q5sTeT5yMVT^9Y%Iop}5pJLwh9HqikrSBHYS=7ao$Tt zQN#Pk61gdfFJB28T|JR$_OaSBYEz8rpy>J#P!<)4KFIfh<#gIT?LH6VvZurhue4Pu zj9;Wgj1ve=U*VD*`KK0uS?*13 zrv#gZ+Gq7h7ba7KrcjtWWWl3)=dza!PCG6|S_&7ghw=J^XbtkP(Dw(u93B{QHm6xU zc1Qg^yTVs5q_aE7TXqo7tf0mBFeqIa2QOZEsO0FKyfi3xsoLcM)&y~}~ z-6RsZT~L=OzaD|A=XvfNqWjGC+~DjwPAI9OOx;O9#f-yK90)n3pKx)GYmcH z*3=4Nxv5mKAYZQ}m(Kxi*tc)m-(EbSFN7y$Mv333Jbop2^;Q|Gqc3doE3vqLgOHnc0493Iladr)h73T z+fvXONfEQ?urgjKv-c8j?FcfuaoALDROP8B+n(gC%nb(sCl?&tC=889`AHosV!iG@ z9bbd3<_{(*^!Z=r+stU1$s6?LXlN=5axhd|$pDdeUJVpy&bbtkLmMS|PPY zir=c@c8QdlEj_WX=u({cGA*WOm^3$=>wu(%o?M6Lfn2CK4Nu%T^LLtI@g@Gv5mV{m zf-F`%lR8)0v6yL=uf4wc$J9SpHwkueuDg{O)>hQ%u2#=&|BMAyDW_!ccYy&X!7DOo z|Ds`;t2i+VOg)i#vM5u4%R;%;|P+nFYBK_QB@krHWKq-Nd zM|PyT#tqT0J}c=mNSdiIStqf&p@1;(CBcqsd#zRql1|f51)-W&tE3n5?sRl`M%)WYuPK8`(!Wo>(7ehJ9M1{sT^~TmOX`x7v-Y(`_CLj5RfLU_942!j-jX^AP zx$I>la}3h>W>fZ^GVLP$?9h)Zk+*iT7EkQA!>F|W?DCOK@v@CGZU|Wo@*dV@StqY+ z_K)i>>~v5|*=~w7$D?Ks8W&-#O9}B72`?`wN~Dv=nx5O` zBJYn;ls0_4Tui7h3)2t+@>kM$>;r87h_#P z1EC~^zhtl)PZ=#Oqx0i%_QZF(AXkkb;fEAEyChcm>yOgSyKjpsV-0+$M5g%ds(sd1 z-3CWTDFKjmxjf~9t>J*Y;d?i^PvqT|#zMEyb)c*L-ON0D5_SC>5jWRLPhujX(}&o| zZ)Z1m+)1~X+iw}AbFCP^jM{N+lf-!1;FKmavW6IayXa8cni!cnbcvc=lw*Zm+LyNP zjXA%*(XY44Mz68$xrrK!?fQ1@>&!eOA1B6;3T zA*RGZkX2BGp{Y$iyyax>x+KS%mroM})+iAqdjbx)m5Lg!n^FXRW^pz@0ToI`WIXVJ ztl%>p6E*m4tRF|te;+39wJ-*D!as9WZgH_a4jK(+Guha>dhl7?N{wF#S)?%A*(Liq z-AQv`PO9boD~Ev~`X<`qnenrOtEY`NGp?Q?VWDJCyDPTNtw?h${*>m_>%^3f@m1-e za7Aaf63A$&PI4BKSEDU%4gBc4oKBObz;S*9soWqq3!1Bui^0sXO6VaVeq!T(d(xXCF{74;)MNVR5xAu zYGJ9SSvHcP8gJs!o=ox;Uw*p1yqX$;iW>!57MJpu7a+u!X4oUc;8a`fjL3bz_0~e{ z=WBFgEhQ|}AL{wZ@uj_}^%Lv@7Xxw_8$knS)Ac`ozb_199SVv(;Gyb&6@45e8OIt8z_;Iq>6*ZlT zHQCr|>Pws=`4mp^tQUKGWx?~MJnBsx--tK0fWfjg)Mnu!H|!oZ>Bf?ynE)WbqcisLvS0$ds~Z{xV&mXk>-8u=!|>0D;3`~ zK!Ab>QRFbq^F%ndi?PIei<%v^lX$;v<*$fIVc9}oH7WZ!XyIgR#Ai&bnG}EIQq$UB z*S}W5i+gsMc%|njb`Znn^_hcs;_NwvnwrC|Dt7AZu-z+_7#by#J@>S7N2maCR3;VQ z+#GuIQ;q($oRzf5M52yFLeVD4(bwAA*Ew~ zMqi>0e@@~0Lz*!vfkI{X(%I}ml;mhX&$u5ZacTd@MMq^LZrY4@zUA}1#s!_KO;tu( zs=&G9`NbY%LKLHekt35i459e?o=4iE+9-089KOPp9N;c8?wefcY$mCw_2pI8E|2cz zNujLRk2qsDsCwKMB~Rl1LA&%gdtqe@on?1sWi01W+9JK&MwmFx*RY0=G)x*V76Wp% zLPhEH=&)f`Wy+Y@fQK$63FR{o^76vX=^l8SY#`hMXYWIzBf*2?Su)s+(@P=v!Ob)& z#wdR?U6Ot%z6tCBRbN`h%)u@X1uDVaJU`vbLB$x{whKvH|94hWSaiUZb&@2=fz-sP zRL_fkVhV~(tEkXkTyqo;V9|BbufDXjy43r%x~XhG{oCvoPfRQ}E<;Nyd0mphoaWI( zk6=;Z66>^Ys*(E~)_TyuecfnWHItsLAsLef0-Wwv=t0k%dhkY|=U0`n`)VfF9*Q`| zZms6qUl%WGU&{nLibfO-9T6{6Hzn6)L#(2eqfMkRKM2v$E<7FELtpO!nMWo9GeQf< zPh_#`q+w}8pPdk+YDlZGiFGPUW6;fb9adb*oCZ`B z1pE5+FD!Sjt869ib*Ux_xdu@xB%rN+`<6gp<>fFj;pzR*iV4Nwza`jB$)Pl2)h*sL z&F)e8c7qQ0^hElcGX94&Y#wFPjA7{Ue9Xb_TwWf1XezVUn;}Gc1Ig;i22Va|n4ae= z=NoB;OnlWCQAYi2P-KbuRb%@%j)|BFvpos?#E&f$H7~DCo-c58uR5PrsotAUw|Fd> z52gL5A?Ki?GH}ik)t^Wh?R|>GDx^VTd#qsi{dtq%jFka2 z!RjPC1dkpNi?}Go;<$(xX9=0?pu6d-pfQz$d^08 z^F3No?OVhCNVfOr=fath4y6FgPEiOP8~e4Pxa${JH$6Art)Fx5ro}?QuWB%kHZ|6Q zIu9y5Mnhg(#|vmnN-Jbrm|xY43;Yvh%Il`2yh76j@r$Ns0J#Ak=+@5eHbHEHjg!l~ zxE9gq0KXg4vK=fngG!zfA|;|mw6-?wu~yTFGe*2`l}Nz(eP;{#UR85d7vJR<3IhVe zyr2V~bj}A9DE2rG=fjjBrKtMFXOK6DnMy$=W7KIa*8B_)t*y~9RnVRc zzMv0AvZAeAVo`c2)mY;;SowEAgOSO_+E4HlhL%28zY=*W@TD?%WtqLu27jGo>Z5Gz z+6-lMlB23xZ`|F|P{6Vuxz|zH!NrhQY?${s#r(%RJPri->|sgk0fooUHw=2=Vzl*cvACYPcOz4qs0HsCSjdK1d|}R*?DQReQYB;sUuA zdR7^p^eXkz$HYh?@c1 zz(D9xO%y%cR_!@=2$nkhsvj~ z?{#BYzQOxnCdw0%UBX>|@ zS!x|JckN2*x?#3|5ddpoq|aIkZ`btC6~fR`S6rbXeua6%C+*>1T&VjE36-ZTEo~-f z#B%*?U~x_d!VpxJAw)8=Rq@Exj$pT9cic;(8G|pJ_=I%pY<&rm^46;D#fyH&5c?G| zrFtDMwBYFbpCji%8=8V`yXdlt;dczHqyy3%S1tnBvuHa;%E4x@W8n}PHBcB3y=WfN zUY|Bo=*RP{nBTNIhcWR>3En8(K~Fj-)sPIxP03q+s5Wd9&yi zVM3tt9OVaf;2*#HN|;zEg5TWBpbgL2&hh-hos-NRSHH4-R=)q?xn0tcb5MDMv9q>*1JnyDurGe8#ijR!yYX-m1Cl_1j`>^J?B*%CZn;+4s^H}^8qpTE!&urpTCDM^RUO^44Lj4gbCxCjciT;}4+r?>;J zQf}1p71@(}r?V0K47_%4w$Sgptv&pXI*zSNEy7vd`nMDRPy{WF$5cQwdrtdUWS12d zrOZ+N@zaE3_Dd5frPz>5FQ7%%!HN&gZBuT&29tQ(XS|nm%}E{30T8-<;f|pBj9jRP zc+ZDe==yA-?Q#mO;<-1z*%>0m6h?%3*nuvaxuh($bIwTr1RDGBR#m)AACA*M9KtW>vwh zWAEZwdFr=U(;~BX25)ys8sB$#$F?QZ;X$s` zk1`cSC`@!U6r}xdB-wLc(Koc{q8BMkU$&RxucgT}n?`wyk$e^HUo=VgHM@GD$5}eI zqyLD3X3^x-=&Gt=ICJyQa^Yq$4w7ld2oID;m4CZP{LefeosE@5{{&$VB47&HaG8;$ z$z@!=BW&mCw>q=@n#(Lq%Cwf)uIbo&Zf<6fxQe!z6zQhN9?c-EsOQp*I!vD7RBxS_ zUL=>GfK#(1qI9?^>T*R#d?fu7&G4W!mIk)LfxGMY|9e9gagg)ck%4cFGud{~d;wX&@OR%>K zr*N>v>kIZ=f2JA}tVj{C2v;6S&|guwJ3bP)S;3xlThdFTU)#F|RBR!i!*tKhW%9*a zZlMFEb7uQINSbYy28QK-L1*eO9MB9?|a@G=o=@Lmp8abgdv_Dq)digRlu3q1|z7YblKobn*lQx4JD2^F`amNE7<2mKSp_F zNgY2Vp*H;FCxA*Vh1+CT=C-f4z}wU|BVQGgp64vejGtA&N}B|!r5a|ei*rL(+bmPm zNg_m3UE9?sDpaWbTuY@XvYpwZPrJ*BKlgx5O`g1@*jGzsm`$(KPDmAu3d6`=KcIVG zDAd8HE%Z=YvI4V$kHz;bwz(XR8{NKLG?v6-(PpiBOxPEjYAoNkw)_u_Skx@&`>>3j z1QZk*C{y@Rqv6_<+=tckAdCIvTDBL@$5k*2bRCO`b`IJ5#p$^3AgeP4(g|6FO!!xl zxdCaIg(ydk)(|Pp`d`Jx>5VL8wK??tkt00FKj)yu1Yr%hRxEA?o}mT|*9#_Mv2Kg= z(^3^B%@5A4Mg1z%ee~x9(AYya>XpZjNgp*QjBbIthrvZ8f-g zh}_xi1|XQ6j$wR^dAvA#ZLs zrF&O0JxQ{DQ+o%Re_80KaYjpBq)#8NXh}zIm%T0;b#f1Wa%DBZMryp+Vl7!aa_0a$ z?149nXld!4zA0`aYA5%+PH$M0vt2tia((Vcv2gdLczv<>2G`^}m7=DV8Ew1>4yq&r z{UOQf%2T$Rk>TNCJEotRzu#u3rNC(3zwZ*;dL2q7yA(s$Z0o!*7*t&Zl}$#=CWh*; zW4kuk?@@1}vN>~eS$M!a*_n70QW8JNe2~prpnWn_VO6*oe$KbqrvFo$UH@iH-=Xe~ zAWSIc@M0)=Ik$VTbaqR5Emr7yfc!|8&4Wx>)!;CCovi*#=UXcIHv>!6LM^Cgo*Ak@ zw7JRKZ<{qfh|VHBvV`~>`rq5#Uei{7n1Ye^M8u60;qsUKgA?{`g9ZhiTH1HkrGo|` zVaa&T#f+rcCr`K+-0TLGc&k|=o$!nr&Ak~?J9#By7Zv$gW)ytB^VUw_pltfWhXCb>Mz#Hmcs8eb2k9(S0w?+=Px zq^Al(idI&Q$>ooK#-1Cjz2~3z5X)GXctS$iDkBm_n!?QT&mfsc@l0}4wniE~Q&8V9 zUN}CDmXb0qs5DSk$1{5RS>0Jqe|2k;(!AR1x=Q&rQOP-UA-A3H*;XB`#)5qVAzuRj zvJf&%>#)HvF$+|W8AT$?)#H9vWM(@>d*`Kl7+fgi5f>sMPw7-GMnZR7_ejdqSqcdT z=^HJno0g#eTK-L7NJ%=qk{X)E=dFePV4DBM*@4NZ4;013&8_;v^!kK($Porp*Q_m( zj=g$>an$(Q9>>OER=T%|Siz;rH>In*|%TZ%onvU+j5GpnON*8^$3hIj{3w; zbb8UYe)~{C;Fcil&E?bi>(|{Nu57&Lc`S7M?Cv)UMoEL`JtO7hE7G%xC{}KiSy0Ev zwRLbN6H`i0^SZAOv0uok!v%rZY=vB`N!Rd-xCI~9M$D@V@hwl!G5!V{vjfY-lrN)d zjH~#K%%(8CxanH0AG_yOzuD?b()Ag8?a~5iS2|H!S|oq&?>llSM&`3w?zt$FeKEZN zUh-r8)8&owit8PjkjeR4_iczV>u(b_zMg!&$BoqDU#&a-l#}Q|et&R#LNWeq!GQZ= zXuu56x8dOu|C$Yq%}JwDBLT)w&Ul%)_Bfd4x^S-~i-)eAA7_)6zR?jFX=&|Xf2HW9 z5!LzBN04Xf!3iuTy_BM|JXiKx8PT0*RfDAt_DL>GS##2#dS!*!-+cR(cH4Ep)1vx7 zWlBl}-9*jcmpJL*%V&WhnWWv+Qk;cW{08MEO12tyy#aHDY^$q$HX`GL(|v}F@3hpO zh#QHgCkpiEhKMmqVSS}8^y4keI+#{jkBed+a7Js}nJb)%6Y~j%g(sUhG~r~XGD{x{ z&@nOg^}YDy!oS#376wyOHVjG4V@_?Vz`i-0$<1MWmkiQJP5B>J)UovWu*@G=k(#K1 zO?(rr2$RgPZ89@agN|7p|IQ1jYid7f+Q3=qC-lkyrj821lT|^wuILPl!H?r+JVZ)3 z-{iA9NxSzl2K=AE*&;>nU-E7Kn3qg+)HJf>_W8=dl*lEBMCuQtP#VwTUZ9nprYF^L z^*hs}^m`!>5w#bwHTZr|GxXjo#-KS&If!2B`se0=;1(gp+4cAA;;D%I=(UcyArotZ zh>@Q|QDH*j`D2UcNekk4OKzB$bfMw@nKKPE3bgcaPSOao<>^q5)jh3D&O&+DF(Wmt z!|!*87Iiy*)z|HJN!iIC6NRqFyIZyN4mRPSd{8CjoZi;`Nc&NGd|z~&Ts5Z1Ph|Zy znjtR^f6KHOVxp$ZTHGfjLu5#PnfSzYr6%#YQ)Vq!7ThR0ul>}7S$+@lIB-)2&xPc> z9ID8Y&-9YkFV9;)56P|xbuqP?9rSkA+0bs)l1VsHRqzUb)$Sa-=7Dn&fIM>l0iFL! zK22$#IYXyTqGB{O=9cJtFK>BMm)F_+AbQG~bZlIGBA+ufJ6Uh>Itl|zaPJK$ODcRa z@~iEZM9BhC0b^c+8ZN@2!7pr!BF&G7SLX-OA33Q~c{uA@!Me~1(Mx>SXBF~mT6psN z9L7Ux=amn3VA<|{9a@QFvMSa!Z4itp8xn;ij7eWN_d3ai12>wDi^qPy<@)K&dcu97 z)|QBM!8{%|>5%7W%#c8qh&IEqT-r=(wD`QaIBe|dPO9}x*H1Emc}Cf;*kKJSg%%q1 z9KmIj{pe){Ez_Znstm$d{vGzBBZZhqbxA8(_ zd4b0H#Nr`F6qu8J7dz4M#&I2d<$P9VHl)2Ok1;Q=Lp7$kb%KZimrpi;l3a$w?>WSO zU{G?t7>#0>? zZtmuTmtqm+Kk@JN&yEVi)a4b#)(~qLI2wg5LUEuYn{H`;CTY!fCWiNl9d`#9lFx30 zB(uj>-Ok>S7jmUsuIw$6c*6Vj1{dEwd@e$n@pf{KH!d0``kT&1JtpNIv(4cBBXG8U zs+ca-tmlrl1im(^_BlzfB(>3a39;?RM1`8i@swho+N+^)mk(roD~gBO{^C?2e*PNc z{;t#1!s|FQ8P&tARa5V&Uo4euBW65(eOSuR zWrxEG>OS#51gd(aIY_sgi?6Q3*sgJhn)hZjH8odw&zwHms43Hg9bTM#wFp}H)zyS= zPwuf@YUY6t!Yo9jC7pp;;i83p2H|I~&!zF;`rrUZ+M%8wJN3#g!EGX^o7p{Bi2w2FlVuLr}|5k&NM%`4?xJtlQVhKIkV}}$?u5Fr=?^G z9{9D!(BaB{w-6#-7mVanj0=;n>2&ri4V!2pDmY=c&*I3?68nL>;`Ues%N*?KiWUxc zJNpY#dN_<>eRXe6_~820`I!~PoZeCqGy-e@+^$@lz2Qu#>}zUJ0)ggvI;bER3zKeT!UPdOp}lFnWub658n zyvFSlbRRkVQwuP=sl37fJi~+cNguY;@zW=RYdvraXD!caZq9Y1wSwO5uNW=-Zdpuc zW?typyilRfMQhs+!uI`p42fJMaOgrVk;@J~sjpAdhPrsXNsLYuxWGB{oH@EzbH+Qg zJdmq$y;gijBy{oW?%|M6s|*Oo`t;-iLm@qCK>|loGLQ?YQaSyfsRlmf_867*^^nX8 zwmlP;*`;MF?gzp-%#NkPy`d5H9fJ}`xvKtkEdmHR6trPQXXR#6=Es7#)oEqlvI2L>9`rJzG*9OL`V3%@QzM4 zff_Swxioq(0IXq-MP&5x9Yj}>8)Y1-F|7peVz1D2te9a$(J-(Xmkk&8e@x>QI-j&@ z%=1DjZ4LPm4>Q==ilo*AyIH=>Y`y3*YPjY!7S)D$YcqN;^Yr2QCPZO6(FJD`D<)C| zmVJFX>|}0CFvxqVH4;zV4UhxQ4=Q73I1Fmw1lgTGpLl}4Z?R(f5izVB&&In^WNl~1 z&uz6rf;)o8zAT1UK&1zdf~cW9c6Q&@^L4w$^l#&lNlTpm2U~9$6;=O!535Lb2uOD~ zNOv>RD$+>}8Yx}w0^=g}y4-C^C{DQ0ClSH(Mx*S*P1GM%BZf zq;BEAqGHm~Pq7$~zWrW81A5-FRm>x-Fh2^vZQLmCtQMG|;aU0oDRSi!FAX;5Vaj&5xlTf8f+p^HfjrO%=eTWmZ>>^+%-AW6V}s((bl^8{Sz1W=#c z{z4XaG-Plgv!$plE6UbHGE#i=U z<4j1|RJlLSK6&7(W7IwL)erGQ3fxs}>xU*9^BWg*WNtty zR;z{HI#y-*zY^XMhaR=pKi5~ZXtuMSRN(!G=Ml-OQ7o4@J4g(uUU;7{HYI%AJISCJ}&=sJS18;=*V{aJN~sd zbII8aA7F@j<`j22y#~^B=_o`P}D^|(vl_Kd*3z&o<6y`+h&yb0~qW``2EcfqiB=z@$u5q((+t?SR0hM zSAd5Tb!;Gt-fbs7o^!%^-oJkj&<31cf7`lG(Yt>g8o|8{pU+c`uG}GfJ469zM0d$X zcW)BtTC2e%IbsY`;)#OW1?LEuURs)3q4jJ^4S`HEjV6?*GPsAG%ctA3lg|ZgN6-y=xYFj9J9ImKoP*AWzI*7Vh8i+Tm9t{MxO3?@sib}H za^IWu+fkMv28bj~lb6D%QU)$MHh-#0Ce_x~3s~M_IZv|{GqDI~a{%^33|92P#;&Wm znSxeMw|m)@RawR}MhXDf)4wNqr)vXQ>|2KUiNIW!>jH(Au1uax4^_#m6}~)s zBi59#B=Wu9lCh5%Q?ZV|sABu9@ztZw{nNXpDt==!2RvsF(kgvIp`a^t;LeO=y!I0A zQT;nXu5BX_silw|+O%O$#%ukPj2is^VI`Op)UOqlh(j^%i6V6ElG+|$S9U*FaDI3@ zxV(0jm?eHk2j7L?%azw}j5$1@0&%d17CRtWQYpt{9i6$JTT>|oi>$}V4`EdkErG6J z2tBf#X3|r^-bHP0vi1Z=TK!XTtil?-@Fan`RAmBbi)Ay1G>YzbLFF%@0I{`$tZcUSy3XjOmQ0WB`@#f|pfZ+Muc0P=Umh`8nj>+zhvma- zL*HmPf_T4$`}e2FRs zV2=W-5!UmbFXe$;GjvMIJnQrrd~zDbY<*5GhrhF}M4ffKUW#-6InNqiU>%?pfjR!! zS)cyXRR0rgcqJ}%t*WeuD7cVmd-A*27E>kE)u9u=@1?ob&_$M$RsxKE?qi?R=vI%Y zxp)cWh^M=@wsaY@Cwxa{kckkBhpd{Lq&l(WjpopPb`inGDgL`)9F*6DKU~ItfSrCA zCgCvp*J>)(DZRE|AlF#g`eoZuoW{PXMEcmiAbAk_Qcd)}`D?MD^Cgga zb6+v0XG(Nfi52s`53`3o?w1l{BQ@s!UK;w}$y+Z6n!|+PsV|DcWRu72e-|i+>$w4- zpQ6g;aU5U2!!alJDS&cw@VPm6V`Y)|@f!Y+`MCGwu$x@tkBR2_c*b}OmAH54xPP}k z_&AN1TvqL4#5gr9Em%JMEs1INaurCy^y3=ILQ=#>)@NLiOh5jXxbm;@p$M+Lz38+4 z*2LR$R9V|LW^j10)H)-tZ^VJxikpg&Y0#lpm{@uwj_}<0gTutx1fyfjr4!(@g#o^ciZ7$~%m`!Hzg&3phP zbFHuYsTrO!JNt={kkAwGi1O@bHLSD3nI-O>fIm)LOvU;q0p3QAC!IIvHr>}YzUw!B z>wGD9><(V&xp$+M;RWFVcbstg6Yu%<>U-_u&Ktw>@+}0)+ZPh&v=Tkj(|9$$JFKM> z0cSsqwrMHvP)gNucYzW9j)&EgU7-mttbcDL#tIV!oU>K{zpakDF^649?lT|d)1Jbg zi>%a+ZTiORKZkP5wn$1#cUve zi{uHd|LLguB}-1JcFqe{ss%_!1@?gHfp<=(b5mR|+T6XAm`PuHq>c^{m0C#|rU=5+ zrSXC@LR$HiM8h;QvqyzBAXkj=6IUqMRJ8u836xCG=LBfcf#grfdvZ|%t}@OdEP_TA zusNYLrpQYD(yvh=KzhA&VpB?vk93gYf}l#)3~l_v2V!RZffK_u1K>1@c$Ab!mBmIV z1?jg>owABb1dOsyJ&!$7QD?8}%UCGmZN~=crSI?OK>59%EExPj2tGlYk*y&z!5W#f z7p40(HB-l~`=eLH)i<0#?A>NQB${w~Ua@j?gk>|fJP6%PW$P_Dc~!mpfgJ1je3=*( zDq}?2>P7jFRU;v(MyIC-{krdWp*x~*es3f;!P|AZIN>;GaC6!N=z4(#eiyk9Y=b8q znI~R5H)mHh0nrK+cSuGL!>NLvr*49D<{GEvCr^d|i5NJ18!_i|mdzeahe2D!#5{}^ zEcb_W9|p|Kv=BDVX}7okA(ci+LaQC%^LrqTG;RG9_d3NXzZvnZGBmcis+k_-rB%7= zX-zBq_GB-6DAV3OyHhmd?Mt_ep?ADa>q~f>Y)e{#HZQ(UM)nh}j+}*^ADo@&Po?i!zSBt@Tq32IpCrBZb(7Ar+w{;L;Nxy`;7Cszk5Rfh`yyGOvV2d0zT^x zhI8}tcb4$Kxo6`ZU5O6<7nu{r7=Q~dtLVoKumsYzTIKYc<_0l7 zC&zM*^H3U*z0MGfOna{zEKG&bsqSB_6bZpqpM(! zVU@v60!#W7krXL7J$fZ9tD#7|NA5tU_os?is8=|w3_~Y}m+bCFibaJLbLc{3|r5aL0J=4@h9hVPp<+uU6e(2vngKx1P8ihM8YD@nqq4GC{nJ%*U$fx$% zCyk7tGmu!9o6ZS(dpF1N^UDvhE>3RIpF4I{d$=sHZVP{x0waq;A4|3(1}S#l)OaFt z`cD18QLN<6YPqp@#QN|<(C5y8Jy;U?CDmi!dz)qzJV2Y|dF?n(o!pb=JU_0>3>YOm z#Q@H=g~3qCitRJs_HcCD54r-utL#EUdZ~+=^K)a5b@LEgaAdPcL@PyfS?Cv#SvLOB zaOB!inBepM$)?wA8j-|_>Kvs=KlwV`pe27ZnzJqSvpGG?ZYba9cxR2ME4-+1Z**ew z=g`30lt>U5d^9p9O}hn*pzy5}35Lb~=zL|abN&kf`*czU+X?W(a(sUDTDzZXK4wcbxXE^vmNeSQ*J}2ZBe?F}pc2zhZtvIzYzGtFNqE~+%k0FmDi$fJ? zYvgOof&8!(7S!NZGuFy~8|YQ5(nglRO&s*%2UD;RF}0*LRbcW(QO>wk*l^R_UE%c_ zMC`vmUI_1plZ(Im`<*s5kp@k3_kQaqKMD{S=8XWmBA1=y&&~sHEl3AMSmy3h8fzo;5XI0M{L#P~?mPFY_vkU|3A8|6pkTNc2}_)%xx z`nuleG4}{kqtHB3;oFDcv{cJ9Y4!1s_QO28FGv|trHQmz8z+W^goY}s1t5;Fv|I|t zDH^omSB4FG zozsuv562GtjQ?Ji?26Dd3)39wveAtJyI?64vuXv^m(zTk)gs-4Lpiw9vVn+s3*aYL z|Hnd+g;pqcAlK&fd(M8a-4-7bfl__V=+u;_yrp#Y_mab4<8Po3QTjt;e{_gYsBtpn z2|`()V~m%)q7MsWB=IBb-_QoP|6Ds7?&|EIT6WhKKaEBZ7xYcRx9P{@u$4wBYQ!xM z!4ockb}=GmEGkS05pBXxk)y;Osb<$G3ifpdvV6gc4 z=|g07^lCMtH;wy?6lfl9D#-0!?nh99Abljw78tQUDe~j@YV-8wj7csG@@3A-F?M8H1`9!pw2WnaVC8#n z)&;N^aL^EzL#U$SdHUVhdzgOTyb7eEOU4ThwK_<8kBElIn0xy2k&7R*M zH#(K6;23jK46G!_zsa*~TA=t~T<{S^6EuTPC)#8gtak4*?(CS{wX6krCms~*wQZ{#AYZunK@8r8a$WDmbLD-P!BZaRVeNwDh#?2)- zdO1oEdNd7@SXq5e-e{4#=eM=6wiS@}6b$K63Sb9*FyK`Qj2A%Ca%Gy)lWc-ku7X5b zZ|g0cjuBJw2DxKJT`2*}S?C*qwZ2q`J0kms`>Mx-D*<&Tg4V4AnEK(qx$6lEEH~g~ z(;A5r-pfIIO%WF&`~|QKPOz*}r1|#KeOA`hH*;OtsbOB5kP>5J3q$-Hrb1LXBj(>3 z-#=yL&}*Ra)kWd3@x0$rWjH=qHe6%zg5RV{e#v}cK84RxJOPrQ8{z4FT7ER+* zYN;ODKWY$rx*A3a&5zIllL*6%{FsR_>==`=KnMl`>R*XNLnf84!ALku5klDMKUx4+ zAt6Q~5Hm;Dt;x99jeghDk%P-&RWn6x6wIs0D)Qvvaf_&XBSp_%NV2FC@Z)PsuMahL zoc;8<%3IHNdDoQkfmlpTEX!?9M_F0f5&m@J(u*k&M~4c`)GaT+$9esD8YZFNh}l-n zDOGjLGE8nEX15Ju{?=znsAKneFLmxeF54Lh{Rn>X+j z#2X+VqEw=A`>7FvdTkecNt$w=d$o-$HdmGv4Wd zwiH>ipTug;m*4b&Kq5ln7Y={?W1tT|n7=5W?}+CN*feT6vN76hOYMHO?7j#@;2ie> zD;*yj?Hl)|y|z%Owx_==v8A-VxculJA%E9F+CRfbNg+62+W-_<+x>Xg)pZCdwmM$D ziI&0Sa7cG~Li(*X*WiL`kHJor=Z@ANWQBQG3JN!3f89vUSBs1M1~{a+7UjKQV=%UT zUa2Mx8d;8*t8mZqcgK+|cu(p^3fmT)e4b_RKKN@@@J4=}v`@}?pU>PjjXmI(I4)eu zyYEx9;(IaH0TVmfY&)zL*=T^MibQwcWp;0Np7?R*0%d2*RwQejW<6jReau5kOWSc8 z!r2G56ThE|rASFW?MeatfUi76EmD6s&h8+=M%Eo#_m{&1S9p124QQ~sJ)YCPdF+>Ns%GPH`ok+-GYk+Q~s$b z0OP$a@pdvVeMZUY#mQf~byIbZKq`4y_>tjP>$^SGkU zp5my`rrZ!l!24y%%*pzfh=bPe!a&S&lh&JU=4>NEmqc1p4U1;5W2=lRlrp-|Y8;l| z^%%B;17KTa+L5K^&uQ;ED28~Zd6zxYOZwu~roo95G}DMW(nseeZVG*?VUiyf8PQV% zUC)S?gKUZkSfVtT0=Y`mE7e(&V{eH`LZ#L>&kLhM)`v(Ysrj z%PZ{jzeJBL>$m6K=S`gcF{$0Vm>u_S4%QmJBZf-EAxy7zMQ{#1#RJ?7 zN;j5n{S~u{w09$fT5}Rzc=F96l}-8V=mAWwo^85=<5)xPr5tNNnOeH|`JM503Vts>)q7KiN?x^n-nYP1*l=O{mgBrr zj5k;wwOB{6P5K}~yPqk&K;2V`lQ$?EumaOx0<>(U6 zzZ$EP+vUb`t`hJ^?aFnY>UXP@E67g5o48nLysCVsH?Ik}7zX`&R%-l?Z1e%&J!Atd zkW$5Lfj$T2tetSqO2B$&5zk>#ON>nGwuxT4pEAK_{cmtY3LfNg|Abk zo+LfbH|=hn%)nQqX%O#$n{Ceby&AQ|@^GenCkV|#=Q3-E&GP0!`IS-zo*XJqvLd4N z&zL}k!u_dry?!@ajNV`M*ZsabK?j9>JX0hf<|NHv4QXQe*T%s~4{i1t@+sf<1s784 ziu}%cu%0!u{fg_Am#LIbgW{Mll+3|V)y$Rd;3Maw8c(8Rnq=l2%1xh_8f1ky#G#?) z83g*IBYZyv5I}OsBcrC6#RAkBc=l>b{iwY`lzEAXt%1KJbNP@&l{${q<&l!ILlzz8z4! zGenpcfuxER(^sJ(>U*JezxdJS7+xPvE+fV#}yr4;ER8iWfA`|BB@PCZL>6p?%} zWfNmGAp@r=ypF3q1rq=|FVY+k6miCFc(o)@U_)XApN73?d7iCdRQm9IK_mgIAE}|k z(9OeZbo-bg3sNEuR%GU0KGp*6KA6L&a@I+RKnngM)GxzPQ)FguL9p(i!Il#9n=ofs zQT~8KVp)$G-0ipRUOS1WNzVLN( z{gb~|1%WWQ>EN47#S#UTQ$paY?~+VY$5!k?nzB6fXaxwunwrdfD!qJ|7z%@2t{5sK zfAijb7jgK&o_e0qq>vsXiC$nsK3B(~`XK^_d~2*s5Gq;PRU2VY%Y{h};i-3V4R`Da zfk{N-XRzlw|B)-flTbW;{KkYf<%&PT<77ZOQeUf#51GNK9QXIyd{!!}7asDL96^sr zBvyeq*#=n`CoR%()_Q7zG%5(ybTCeiBVDqV1SnCg}3TM&m`7-#3zu4sEAb%ZO zVW!YabysW&7cEf4yfv;I^%E(-@uE#;2)a(FoSNF3k@~l!xh4AbWwR_rWppZUl*+@Q z#0C=gbHh#qQ(tGM+_IgE153zt!vO{@gt}|pdcG1dZjnl7-mCp{4(weH-NjI?pi%5QuHQzuvZhiS7~s$R1o{iKS*insinPs4bdx#t?qMOvpnC z4`R*Ft@6Xh=oHWXVJY?QoJf46!teoD5Dq21Jz$6T92q^~&37KS=|5$`+(?QS)A|jA zzEw6!Lx9JeA;x5ju79R!MOTOs<~a#ASA!&*&sp5)icR#1Au+v12nml&=Gt$n3e4B* zu|1=8@KPH@NHMsDBP{8R#%t5pyjGd#R{o(gu{$Dhdi&h`oX(g-wiB=5k*_0cMRHL! zcwK*${to1ny($8;8bw|x7$|whTzUSLxZ(v5BX%bn7rNog@f$N=Ih}@aA2=9~H#?yb zE(v>ISA`}zC$0GOXW~fLn*Yq5@4j60h4u#gc60Dz#1?CX)h>(RdM(Z6AH&sV{D%Jg z`QEjL*7OlimOEPhN2lqBG@yPJ%-hy5f&>1|*gs=^%1!rx^HB8BH3Awe4>7eUiJ2q; zn*Fj3R}pD+(1LrFD)wixqi}!epkXxGIW|cH_Ek3_8IM zb`6K7F@YkWY|9gTn6`uYS{z@%A?*m271;C}^$QfOJ9nd_{67VJgA>wHC`f~Fr>`Wq3@3dSN`&? z!;iZ!`b=Z89(Tap+VBCwhK9DMQH-PLXBZ z<|UEyVe?wVq#axSX58s2xf?^LaJP#TC(L$P(ans}^umpd_kD{}Bie=3@C1c#;8__` zXJ)RNI?EOTnQN~obydb`YHw~D60OgGx(3f-K zmsR6`I`K0J4dZHl!Do=s>4+_R39NkWdjbWn5SriQbo$}n_-=}cK8|6Z7gTTxf6c5g z_sk3X_qK(r)!4J>*hj?7uzRf5HA^FJ4vE{p?f>p`cLrPUy~uGBe*wRa4d^+Q#OCz~ z2rbR+@|qH7Yo;)m_k6sLJzYxGAERA=#ED(IrndK;`c$zN`!8?Ep?o*qOG3kv3F@?6 z6I86**m`)G2yq$oxlpwV#?ekuGIB^BBSrrC2?W$cK-+4H&pVSzQI>>Kj1q_=ff1{S zLv-|WXf1~&G~Yu+ZKRWry`r~*{YrP-+V=O2%UnwJJ7;3v&o{)mX~y2*@xS`nt*uDL zX%X2^op1OZNX($>5>I00Xo$!VuBCU$*nWn>;2L&LGv|`=wJBx*-APZk!y7~m&Hunk zv{>&I7cJ9yITI-uvs&%qdwSjA7w5XoUreB>^vGpm!LK)eyN%&;!9LAbtj|*G1)<6e zMc%7Qc48B0xE1fOsZmApA3;w~%P@8I4c%{LP{RAbA!JK-YzbB8oUP9^XQ_$*w%p3! zp@m;F)yJ;&cF9?||6T360cu;dDO;+QSMUv>MD>lLd^(i~hwgow07!+L_JD7bd~4V1 z@U+yft#`f;nd@dZ)!E2wti^PvVi{LDk8@;gigo1Zg?bN;If};gc8P9fa{P zcJB~F^z|Fm-Z-X6t*ZlHMwMxEqwkcH)_ir!nbuA2+Ta-{f_fjADc^3%TQXwVuO$9B zT!M`uD$CIxMoU!~2Z?O<`u5a&-1 zmi%U8;(x;%O(Gz)Ur8U!u3^^uBF8;>xrIUwRKb$-t{A;N^#)*ZXg^?Z^FWG*82&Ey zBkPwUB#Bl0Glg{uSni2;0(k>REWe7o7b=U!&jlII-;*gv`T>yKtv4LM>J2b@rRP;w zT7M>L^%)G6cArz~yZnK)cf-d5eDH6?+7cU#&W-N&5n?Zh;4quFnHkW{(rZUIpVkTv z;V^|95@TEII?40YZWnyOdusl6OalJm`ztiqq>Z!55$S(lA&^&X!j0-|r8&N5$m?woX?5AitOOh_8qi&?QS6B&$)n3ATh z-MT+-h~;igtlwvRI#B=`{wW!h@8%?zb1WFxSCI7&Vr!X65czpGmK~a289$86*;?hG z);oswnq29i2wkz)+f~ty;Mm<^q*tQ%|VoSR{KGxWL;%FCDWGNW39 znTVM{-`l4g1M}KKy417^w3nnAPsc2U!y__pa*em; zH1eG$su=u0F56|g(p4zf(k!7Y-HSlIss#gcj+o?cu@>`}OdFrk`iw#9G4JgAzigUl zNMX&~wZ^==cvoMv-V?~l8h_Kx7wOYA!Ui#0H&GmSK5%423u_S9AC@tCo_>Eo4g5x@ z3XBWC=j={c+;{T7PNc+_f9c_WvW^<`VsFOe!fJG4!^bTN#ASzXn(h*>W5l|})Mqnu zwmTSpAQGO@j*{vrH)hZmoh=)k9ehPz;VlRJdqw{GLJfB=)muzSdp$%zLdnm*&E~0t zB!SM@-6G0Bgu>LsIZLxCjCVpj_sCKd0piSMm)iAvEWIjV`OOz=TWsUKnm|aBbDl{fSR)8>@l_kei3=n^yrd-WdOPy{7>esVtQUp40L-5})(^ts{(VZ@GbtIb< z4?I3%H2dG72Y*+4?C0e-g7vc8kJ~?7dX}|OqneVAZk*&g1#-H*k*I?{q-n@kC9MGx0{?X_Iefca78E2?kucR2u0Ea zD&om;^F-INJ>*>vftdASr+;HK({-Nb4pnwZC_!I$AJc-G})|mr9!S!0P*m32RUr=Uk)>b`#PlZuzfw+j0pL--o zjdRDEGUbQ@f3s_`lDEy0u{7HWOQtt-p~VYb;(61fE(;HPH9(^4q``cd-|%^O{ydPV zGfAx7<8-XXHyzfo(ciIcUb8{D{=ngXcaiIOW}b@QNYbYizE&;JxpHm!`z^B-8EzQn zN6|1U*~Z=+Z1DW64K5hJ@VnR)83cXwtw~E~wd{jm7Q?gOcX)G&HhfeDF>TGfeX;HHB?&@Cm7}=08WDRNu^k56P?RAh4qxySO-0W1 zFwtz(Jp}$iyRdD^5@uSfg5 zbgOc^)+qeFCk*ucXPdHIj_k_mP~O~oruF;#?z1+d2NiqIE1TPC z7(6|Uq9gY`N4v?Curfq?UU{0&K*MNLn>P5@45lMu7i9rngjMBeG86Do6mf_6M0sMn$M=q92dj?;JdgQ({^XUpHnio1TbfSy*E(P#*ffpp6yN0-8&GG z+Lz1hwfar_fP+ECLho8Ud6w7p9R`M-Ay_pIC(xuAl+gz~9_mblsI<9d5x7X9;A$my zy+QWrZew)(!gdr<>{9ii6Yl@Ogd!_K#NryNQ;ioXN8dE*G=i-tt@5VoXz?9MgZ&vc z2rK+nVR?syf+vqZS`Lxdp@Ba*p-ZsNxcxHj>zKdW#WgLsy?jpksTB?_xDe-v!Z^Xm zva3sqS_+l}nTR1g6-TxnE`TQ*KpPqP*9VHXRnr#B4!g?reD<)-M0TP? zcpb{H`0+Z;_G7)3tcq*MVt+*at62)#a@D8h>j~BL6}dn=m`Ab>8|8^eRmpyuMd`;Z zRTFLEISA7%*!ljhM)HrJdDrV#Qyf)!nG7Yy#%V{XP9~Nc?t=8PD*_#Vg?vv2Z#)8W z)6!wXna^=0&DsQ=@H&Ge{V??LHPzO=^Iy<*tgkj*n;PsyX%)?co!$DG6~@-pst!$~ zGqw*f{inFYrv`oSWcY*3S0xI3nR%$+%`;lu84eCY*TyPW0#29e-u*#tvQg8z zc{kFfvXw-I@>4*JLsWd^Izb}sv5LqJBlT-P8BuFxd{3Nxhybw~C(~-C>m+~Iaj66es!p9NC2^2% z@}roNj4>D!o2KbV%9oXb>a_DV7Fv#{(q)r0X&^~Vk>S0{w$14Dpr=nO(sefJ&2voj zR--CZNk!U~FK}MJ%$fgXGj1w~$TCZz-<+jFSbes^jDc`{yw-oTe#=th)jMXp=uMId z&JMBAsU=!-4w?!l(tkMIagcNk_$s}bCNAZ|2{lga!pvk&viXYMr&CNYwkryO zwsW&5HcWKJ<*Z?jptU^A(J;+>pXs`ZcB|HD4_xSuszy)q*5dkM(qxf0%dY>j_y<+& zlYpTVPMQBb1&sXVtMfX{C03@399ATzWI>hrO_KjnHa_h9wkx4lL}z}n()kMpyQ2*g zJI9o3fA9g_id?EV{-6_3S7)nI z7!qO7`J@nNb?`Mqg?L-qUUj@q64Izlrf2L0&|XZan%g_-G2*XO6w6fui)E5H2u+HY zK8t*UXwxl3BEEMI>&*6UA;UT0$nas{-pdg?e)ko8WSEL+o)%KNw zFVkUiIen9%%{VXn*E`1>SYK*B_P_q#0Uk~22^p#0IT61~K7N27RvVp*IQTMG+ntr9 z8jMs?-XaMGxb023%smVhQQ*c5T5rEI9~~7~?6Sfc;;}~d!LCg8s=fNBC6EZ@ zqEY%l!XC?4gXkhn6TD~f={Pq3Z~-h=w>Pay)ML;H^{DlSRugA|8GA_^tI0DG_p^tUAUc%s;kPr)059 z60E_n^;#qNP}p{{@q5Gg!tmUf%;k+1GvTUjpmE4y63fU+R)s)%jlf&VTw_;TqzP=M z7OY;<`vtz4kEEg zKU&G(Z2o1B(M{ky4ye`()8q^L`)0^|Jy0IfQ6V9nA?FzAsAZ z(+Hloo&G8C^_|#jB(b2(g~lgkppQ{6pNYx%hK_S9K6WQ$JAWkqMWp(Du~wlr2d!dy zI+?NS%|Gdeg}X(dmT8V48g@mFDlwAi`6R-M&xC=pYLxLF5@*}7uvtc}`Jp@6;7-DO z4wH#Q?6^K1@(y&4wxqMpLgko~one@0DwFEnIZV7a^tU)i%f>5~CToFAtru41!0FAK z%@Yz)wXqMLSx5ZCmVq`UJ54AovaTJA!uPV8+=QopdyO%TjFdXE=NQk4tk!an_OIu; z#uih4bAV_6d}N8$CAQrF^T)4VDrh0E#_ri%Ac;e7=H$fp=Fp|;^z-?-g6GeduTn0a z)&4QmWlP1Yc}I(uB*SC$Z$xM+SZx{7-4<#`Egc}`uppPuWo9y3S(dC(-!Z_KM;Iw zlB|659`?*una+CM4?kwzXSil>nPF;%;(1i!()b{yr9>YQI-=2&H3#dlae52cqn4`o zxT6D?t2vEm_GPz=M*Ff`A9!ChKE_c#JsKNc&voyXi9uH<;Dce^zmT6Fo4vNd*mah^ z8O_}f_^T84?H7jjUT{ih=*d&Sd+<{#kTKAenSGj3$_B~z!wWIv7dDv0)yhWiRih;Uw0Yl48E0<2tg$kmZgG{PTy z@NRxFRDOgJ!=z}qVD-U!q$Q@6LC1{|AH=*xmp_Yk+8aj~|Mivah)HcX@*p^6l;5Dj zI|=U0jaV1pMTr-R3j!TK?XT(w^hWDHt)!mzC90h*&|*9NmP>U6 zBb+*hqmpnkk6%{R-;6g&tXaIgx* z;!7{#fP7BRjhKG3q^Uic3gqYYC8g6`6HcIWF>-pzjO8FR+IOpLLHD%(l9tVn>ce2E zxJ6pM@yISH0ccc3EiXxTez63^{Az;sRMh)kU=kt_j1zdl*@BZUE9wd7yxrjp_;U@( z8F=$qA`_j{k3pjKK>;B7O|yK~5VQQRy&l&@a$f#DbU~8()wiH(M(|}B%Y_$TTeWT# zUeI1?M|Apx1nzu(c+99a)iaYCjp&=~*I-|cPjo3Suo13{jB_?udX+Ib>54%A*+`ei z@`~v-n3_3_Su?PN^`l65a}|uk%8s3|WQD`tF}Li)Ajs?O`yJ>V+gRX0gRR~yGZccG zJby-Zr%OFU0@?!vDYn2qyQ+-C$p6wbBgq4@4H;@7ts0Lww?dYDTANh$sH>f~g__88nRweM!FQBBAQ?($dV;F;81{evRWRDUe)3$*q)f!#ZFZ2lRhjpZ(!c&@=@~|8LK06eX4xx4&cke`nhJlY{Nf($)Nv zOzQe79K7*8d~e*Zfm!dvfTJ;{;@g!{i9Z{YIGmnSZeKIL_`64*opFzgKDEYS_3{-Ui}d9r4HeL=x>i42_FPEm&p+W6Z$rQg zF&FXdQkeK9&yt+;u9c%WVN^9{IxDwCyUc8U0=GHi9|G+{16&zoPTC`1X)M^FEhb1T zY>(p^uxbyj6d*)vX%vb9&g3!}_;yQy$i$@@B}z$8uaT9|hg%Y#Od{-c zZwr+1L0lL=XMl4w9hs6#vM!TxduU;QZl*xxWda`MR2b2*sA8C0ZkG1@E?19(rm~#s z#L72?)mEa%+ML;mP9!qwbnzxS>Qw*^_mW(&IB(L^UD$Ox1r_&(Af6c8yOkFH306^Klz){K@ zJUmidDj)F5c%;%*@ej>iX%1CW5Wdd^4NY<+rw=i!W9Xu*p!OtR6b09 z#4AMw$l$DS<#0)<{4d5NNMBzWKqi~~nk?U`eAz>)HifqEr+7W`eizna1f+q)I?>4U zbo9!UM^9 ztYXEAC^>6dNZV!6DNl?-1qox!aTym|u?y3f3 zeM(w;1NCIyNXU+>uQL1}$5SHm!ddON^h!N{FX<3SLlq&x562H`sv=Kpp#oSJJw{#}P*Yk_$Mw#?s|}=sJZYKP zyHPG2yIl_yu+1=vFTfH`efPUJD;{wCVB_#Z;g3G|W!IOSXo^Z(#1l4LB4Ux@rFB;= zB6(tWEaPT_YdmzCGu%gLDdxPq@1$C%U1U?1!G}CtjUi|8zDY3R5Afb^1bE zzdITDte<3nrfklV`Ev!a!W50@Kgi4S$wUatc#rl&gni{-9RsG6v>f6iU5pw=fOa(w zhrQe1CpU3*ea%qfdCxm;)R<*1r0+Rpp7jugPQ2WnN(tXnr3l!5X;E65PDW|`6$(DC z2lm8>x8c9JOR5lC9n~w8+2^!^ z^;7Kbbx2kgG$P6QlZ#ijP-~WHkY=EvK#`fy3<7?Bz3qy<*m8AM{R^`ct%{@d0sroX zUxr>0Y%5vN_x}@%SGoX{dilZhbR~8Qv$?XcH0j?-E1T}$1xuAh@crVi{YMy+b=ypl;Lv6t$ zj41@J-vid1HH5yOaTx)fZ2|+cQbuP1)jkJf8!HarM?zNmI+-T4I^QaNk~LUT0E3Tu z()Bx_i{Hven#tB>T|(pePF=B@QItUUr*EGwc@^VxIw*K($+pRNOOOGKU!<8&?q1BYvX5TbfM%FHAbi35ZEOFyv>@+K`zvv+? zX=KqUB_>ftI@$hUQnKO~3#6)GwbCJc^7}+KC|WMP9U+?mDzPB>2(o8b3B}b6G&Z|g zSgEp7-!jG?$$w<5~-50!bDiA75FLm*Ev z9ORc*^4ZeGsel$iGaM{4IqjZYVpV6p?9LBtN87$d!Irqi0XLl7W%p4hnzqMj)GGc8 z8I4@1wIykQ04zoC=)Iye3fVF}7Q!^$0GC=+-FKWr*Tdj=L^>ekS7Pq7B+6p+ zN|rr3oNDL4{&grrl_y}syVZ@T@BH&fckpus0xOM$jExP z_YcIj%uW0brUAH=OGKpZDJFuc4QcjxjPwP^ONut7CSwH> zV^l|r?%-dQhSV<`Pbs1RJxPGP_1`PtB6r0n$EL}Xfu$M2>(f%~CouLbugI*Zl-M31 zakROT)slUm+_OMXg3mQ3UOOL@l{+&C{xl(ZwAioUUfOl?n0tZ&tQ*EqRF(lgQ!iCn z^|m1QNtshZs%9uI{Jxn6jYdYnF!v!qQrR z&=juvv*~M^(5tm6f;&m_p|)xt*Vu4|Unk5`%ia7grpOYV#`mU}tk3W{UzT{Sp)bzQ zbUwLK>J74*&ipcUATdNHa$k#RT2p}&v*-Mcc?#sm;ChW7F4QQAwqM(x`oA}Jx;z@x z%%Lo***SC$_MU*W=`i>Oiudi;e}7weGxm5P-RNr`B7-kI7E_Y(- zK5yNDITWW^yI4oLhhTWsHq1qUG;nIlhbzg^^wy}eiPp1AKKPg;A!}@4=nXUP_jSSQ zkp1U#0aujSU1ijyvDZD_e<+!{Do4g$hMAaO=$?4+#IR*h)?_|?N{kYoAqyp zJi@S_g+q7*uKOJ?k&L=F?bycnPCst3b}I>uEUhcYz6i)FR=IyDV1>i~wkT317=g_4 z`9};G6-4^p5GoSM_p|1u0+M6>#3EXaPX53ZhOH<$SU$x$H1*-9*MR+l(Z12GIBm;* z#dkLIc`{k+-k(c5dR|>RgO5oJC?Ai^wmjb_3#R?jh;IjTr~fgfG=QS^Ka#*&-oDuR zuLQXcx$5{IUc?-3R&K7cV|L4qF zb`%hr*_yvG&d8o3cD?@-QQagVs2rt3!w^#8%dY4iH>w`0#q+^Vzg5k?$fiumH3c3~ zMVZYSxWXkKROwB39)%3qfhW(bWc*!?ArNu{9d1=f!Yv738C%u!RsF^@pD~to>F_h73G?Y4OX*!DaQN;F9I><6u0u z*?w_!Ztuj1WWqt{ImTtq6Ns04xFSZ7D0{`sd~4Kp=SW6GSfvoXXJS2q>?Qt zD;;IR&G@)r`!^8)v01^$l>@%vPr&`&lcWavtqH?OUqui98UPC5e~Y))x?(LmGfvnl zZajz>jO+LAAfd--bi)TL&3d=}vGwkvBY-fbL6{||q=ocQ1WQw=O z^K{+-#8gZP-DG?@>FjC(@oS+4((ed4)bs(}HZkY?iPxON^QVj7mRv>VI3-f^uk(r& zjc*@4JlDhZGe7u0mj^pGv(yN(9*--X80yLc*)E4rWx%bnpOuD%>r~_sQH&qT+X}s& zc!Geu<(M_<`!<@SL(INiAvhc{x>dzP@h|(?#%c%Dgs`_~FCb+|@6jVOYz=iJLPKMs zN6`D#=Td`kDr3r7GZy`f2nDC?BbR7=~s{ZqTwhNW{>}u_lqN0mhQH2K{qzAhB zGZYUMwC&M$DDtT4zgVv@J#oHI8mpQySbW6`*K)JNK~t|)uL3Ku!EZzx_k}~gVv2M} z#8q`y5qsymrq976+=wC$wnJtOvtoVDRYWAJ`^Qp{>}#$_J9}%rhV3!O0Kk^fs`sU{ zX8aB%aqNOgXGmv>Cx(Fw7~+X=HFRyhbVgNgUsx?vnFLpij!IVqMPD0^sn!JPs>j`wyACQdodQ@HOt?9X&OHdgqtz ze*2cd4wBRChJM+3Ar4%dFGd2UStrrxizUB~->)nJg=RWd6ob%b?#D$Kb0`F6>N7NT zgY<(f_#;E#PtTzlCeqaN{ec{{LqKR*zxQvVb=SzC2oo1Aq{jKHtL$9?^PzoAu~8B+ zQiD*w$-TAg;=SJMat6+{0gwrJ=QLXUWcww(N0kvHXkf~GRjkMPk1kgxM3`D5Vc-5R zwBg)b+tchk``}>xZ7cI=f)X?7APBw=q4#Yy8X4_R*cM0 zcW{gIG^~Ak)(eT~%K$N}>($!=#+6>YM+^^%pCs#|_hZ=)g6VzV`7oC~!+vxc=m@H) z92WPf*qL0qz7AauwY@0{IPiT>llY0OGE1ty;LB9ciI>5yLm5yWD;>bimj|Nbd}=ky zVDL3}V$EfyyPhURtj{-BJt)nAEk?fL`ALg;{?DJu)c{|+-qo?Vi#m}h2;4otysZfi zFSt9z;{G#o)Q|3ruq!C?Az)DG`!i|9x{`4~F8bsU7Zj|=UoxHCl= zLFhmRtziL#=Jh)}-(fOZIfRmrjK#aNj zHbPtB$C9;E00F9=gY3AaI@lP?O4;#W@XKYt-w_N@-BlLGcqV(a^Jk5fwt=6V$#`dE zT9lFg5}K!qi!lMiIcyhnWO`2=a!dBa7Sb5vzfPHaMhHy+yd7}F=hi^!73D_+6i2QZ zt_K~24WpuCV#z;waxR;>)bc+RE}w3bF44vHhnbh~znn01U&>8jHJy6P*$ zAH^L>=bgtm-sksGdSoQCxgxztQ|*dgt@}PpgF|$TsR=5tmKo@EBKNcaM6|=IFFjY$~vKK&Y~~m&2x%Ik_%1w%Sz7rQY|^l^nP%_i2Ux z3+}iZlKtBU7WHw@)G49{9yg0Uh-O5sr!AQ-^6Y5kO@aO56?GO&Y5>D0JM!sAVC%-2 zWVV=Z1Ummt7?506O}89;8W9lph;N-UDiSL)n4Y zsvrAV0bGLszm!sny$YqxJh{ozhwMF*Wy=Y0vkgq7vTyqM!k}~5@2>M+o+eW2?Aih; zF876u$tL8ABVp%JsoF;F6DROQElnnWwQgQcp5NX;j{n&+Y1%wTyZ3EVLGoWi*Ff4#?rEdgkBTBm&9Fdu9I;2HIby&6vvs`n z_yf24N@1O$mudFNk*ci9GGmecB{c0V$Hn4uW{!I6t(aIe|lYUvvd&0g7EH{&+ zAs`eAZY!UJ`-zlzLXh7FpHa9ZX{$|+?MYjq?(j7!Zb);q7bCjd`q@Z3L$?>qUZIXF z$Ppo5!~v+%BO=r+lI4eyqo;27>*_o!a3iJB{buTCL@+i^@}QuRcOElkhJRWzh|_>H zj^An567i6yjPlr0BUX;J5w7LGGSwH?&WcIXgLo;T{O6xG5(GbftN{k#sDt2W+55`S zk^ZkcV{izSDuu_yX1jRp!DGSXFPHNH zjmkF0wwAxC@QJ{jk`n{h^w=8J7hMKwkP}O(j0<`JH^i%#*kkf))D&)%^425^>Fc$w zcKiL}R|AcB&}Y+O^u)PzS4Ex2-6^}Qe7EgMp5K}nZ?TQ@W$OKD&E=i!E%Sj(V5+3- zSP%+!B46&E=yux$A{8I- z0WN`)v|O&fl(0r>E`+G;k!~slT$NZ^C7UO1WqvLSQtt0UrHsuPV3R~g?+@6>phdpc zpOB*iQ!VCyzo)FV?Jv@0;_GI9`xCueaMGq8pLeP>2UX1YSnU^2>^h-(Ed%rY{vnXp zd-^aS*n^KxnyC4|2b2sG;0drX5=&<)m4^lheW8p18S{99k#(+8%iDcC1^aP&t#HmBadd1M45iXbA< z6^ODTj3P2(8x+jBbxV|^Vj;h`g(V@xzn4FFOo%7 zceBDLjDe}(q+gKrqwjgiL!Hy-2yPOT@6`3wTWbhm-{N@${1bZq-{n)O8FAN6^vU+q zoDxpCFHgD{K4TYC3<~yN(xvM>9BG1xbo=%+8b1)ke~hv=QTe)Q&D-EEsv1#7Fx3Wh`=!Z%`0+%2n0( z$bR=06%V zN}|@skxWAY36bJ)YWHv3`K}acTH(pB(g>OCfC1a)7PLi_{of29TRXO#6S1mPBvwRo zuS&QPB;$;;wC?gwa1VZ+ahio{`CGDf-pr+zK!C^7vQn`*E4KXfH&j=_?bPz&$o-+k z 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 |GJ<@47bArecObzai6r3CmYb?=S{UU+`K_ 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 literal 0 HcmV?d00001 diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.hbs b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.hbs new file mode 100644 index 000000000..09c98431b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.hbs @@ -0,0 +1,146 @@ +
        +

        Android Mobile

        +
        +
        +
        + +
        + +
        + +
        + +

        What it Does

        +
        +

        Connect and manage your Android device with WSO2 IoT Server.

        +
        + +

        What You Need

        +
        +
          +
        • STEP 01   Android + Mobile. +
        • +
        • STEP 02   Go ahead + and click [Enroll Device]. +
        • +
        • STEP 03   Proceed + to the [Prepare] section. +
        • +
        +
        + + Enroll Device + +

        +
        + +
        +

        Prepare


        +
          +
        • 01 Download Device Agent into your Android Mobile.
        • +
        • 02 Install Agent APK file.
        • +
        • 03 Configure Agent App
        • +
        +
        + +
        + +
        +

        Click on the image to zoom

        +
        + + + +
        +
        + +
        + + + +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "bottomJs"}} + +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.js b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.js new file mode 100644 index 000000000..ad4f0ec9c --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.js @@ -0,0 +1,24 @@ +/* + * 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 viewModel = {}; + var devicemgtProps = require('/app/conf/devicemgt-props.js').config(); + viewModel.hostName = devicemgtProps["httpsURL"]; + return viewModel; +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.json b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.android.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs new file mode 100644 index 000000000..8e1900d48 --- /dev/null +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android.ui/src/main/resources/jaggeryapps/devicemgt/app/units/mdm.unit.device.operation-bar/public/templates/hidden-operations-android.hbs @@ -0,0 +1,246 @@ +
        + +
        + + +
        +
        + +
        +
        + +
        + Configure +
        +
        +
        + +
        + + +
        + +
        + + +
        + +
        + + +
        + +
        + + +
        + +
        + + +
        + +
        + +
        + +
        + +
        + +
        + + Configure +
        +
        +
        + + + +
        +
        + + +
        + +
        + + + +
        + +
        + Configure +
        + +
        + + +
        +
        + +
        + + +
        + +
        +
        + +
        + + +
        + +
        + Install +
        +
        +
        + +
        + + +
        + +
        + + +
        + +
        + Install +
        +
        +
        + +
        + + +
        + +
        + Uninstall +
        +
        +
        + + + +
        +
        + +
        +
        + +
        + Configure +
        +
        +
        + +
        +
        \ No newline at end of file diff --git a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java index 60c29fec9..9949b69ae 100644 --- a/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java +++ b/components/mobile-plugins/android-plugin/org.wso2.carbon.device.mgt.mobile.android/src/main/java/org/wso2/carbon/device/mgt/mobile/android/impl/AndroidDeviceManagementService.java @@ -1,17 +1,17 @@ /* - * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * 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 + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ @@ -36,23 +36,12 @@ public class AndroidDeviceManagementService implements DeviceManagementService { private DeviceManager deviceManager; public static final String DEVICE_TYPE_ANDROID = "android"; - public static final String DEVICE_TYPE_TENANT = "carbon.super"; @Override public String getType() { return AndroidDeviceManagementService.DEVICE_TYPE_ANDROID; } - @Override - public String getProviderTenantDomain() { - return DEVICE_TYPE_TENANT; - } - - @Override - public boolean isSharedWithAllTenants() { - return true; - } - @Override public void init() throws DeviceManagementException { this.deviceManager = new AndroidDeviceManager(); diff --git a/components/mobile-plugins/android-plugin/pom.xml b/components/mobile-plugins/android-plugin/pom.xml index 0dbcdff77..788433cf8 100644 --- a/components/mobile-plugins/android-plugin/pom.xml +++ b/components/mobile-plugins/android-plugin/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -34,7 +34,8 @@ org.wso2.carbon.device.mgt.mobile.android - org.wso2.carbon.device.mgt.mobile.android.agent + org.wso2.carbon.device.mgt.mobile.android.api + org.wso2.carbon.device.mgt.mobile.android.ui diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml index bd997683e..ec1bca777 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/pom.xml @@ -1,18 +1,20 @@ commons-codec provided + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + provided + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java new file mode 100644 index 000000000..c637252a5 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java @@ -0,0 +1,197 @@ +/* + * 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.wso2.carbon.mdm.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.certificate.mgt.core.dao.CertificateManagementDAOException; +import org.wso2.carbon.certificate.mgt.core.dto.CertificateResponse; +import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException; +import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.PaginationRequest; +import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.beans.EnrollmentCertificate; +import org.wso2.carbon.mdm.exception.BadRequestException; +import org.wso2.carbon.mdm.exception.Message; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +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.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; + +/** + * All the certificate related tasks such as saving certificates, can be done through this endpoint. + */ +@SuppressWarnings("NonJaxWsWebServices") +@Produces({"application/json", "application/xml" }) +@Consumes({ "application/json", "application/xml" }) +public class Certificate { + + private static Log log = LogFactory.getLog(Operation.class); + + /** + * Save a list of certificates and relevant information in the database. + * + * @param enrollmentCertificates List of all the certificates which includes the tenant id, certificate as + * a pem and a serial number. + * @return Status of the data persist operation. + * @throws MDMAPIException + */ + @POST + @Path("saveCertificate") + public Response saveCertificate(@HeaderParam("Accept") String acceptHeader, + EnrollmentCertificate[] enrollmentCertificates) throws MDMAPIException { + MediaType responseMediaType = MDMAPIUtils.getResponseMediaType(acceptHeader); + CertificateManagementService certificateService; + List certificates = new ArrayList<>(); + org.wso2.carbon.certificate.mgt.core.bean.Certificate certificate; + certificateService = MDMAPIUtils.getCertificateManagementService(); + try { + for (EnrollmentCertificate enrollmentCertificate : enrollmentCertificates) { + certificate = new org.wso2.carbon.certificate.mgt.core.bean.Certificate(); + certificate.setTenantId(PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId()); + certificate.setSerial(enrollmentCertificate.getSerial()); + certificate.setCertificate(certificateService.pemToX509Certificate(enrollmentCertificate.getPem())); + certificates.add(certificate); + } + certificateService.saveCertificate(certificates); + return Response.status(Response.Status.CREATED).entity("Added successfully."). + type(responseMediaType).build(); + } catch (KeystoreException e) { + String msg = "Error occurred while converting PEM file to X509Certificate."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + /** + * Get a certificate when the serial number is given. + * + * @param serialNumber serial of the certificate needed. + * @return certificate response. + * @throws MDMAPIException + */ + @GET + @Path("{serialNumber}") + public Response getCertificate(@HeaderParam("Accept") String acceptHeader, + @PathParam("serialNumber") String serialNumber) throws MDMAPIException { + MediaType responseMediaType = MDMAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + if (serialNumber == null || serialNumber.isEmpty()) { + message.setErrorMessage("Invalid serial number"); + message.setDiscription("Serial number is missing or invalid."); + throw new BadRequestException(message, responseMediaType); + } + + CertificateManagementService certificateService = MDMAPIUtils.getCertificateManagementService(); + CertificateResponse certificateResponse; + try { + certificateResponse = certificateService.getCertificateBySerial(serialNumber); + if(certificateResponse != null) { + certificateResponse.setCertificate(null); //avoid sending byte array in response. + } + return Response.status(Response.Status.OK).entity(certificateResponse).type(responseMediaType).build(); + } catch (KeystoreException e) { + String msg = "Error occurred while converting PEM file to X509Certificate"; + log.error(msg, e); + return Response.serverError().build(); + } + } + + /** + * Get all certificates in a paginated manner. + * + * @param startIndex index of the first record to be fetched + * @param length number of records to be fetched starting from the start index. + * @return paginated result of certificate. + * @throws MDMAPIException + */ + @GET + @Path("paginate") + public Response getAllCertificates(@HeaderParam("Accept") String acceptHeader, + @QueryParam("start") int startIndex, + @QueryParam("length") int length) + throws MDMAPIException { + MediaType responseMediaType = MDMAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + if (startIndex < 0) { + message.setErrorMessage("Invalid start index."); + message.setDiscription("Start index cannot be less that 0."); + throw new BadRequestException(message, responseMediaType); + } else if (length <= 0) { + message.setErrorMessage("Invalid length value."); + message.setDiscription("Length should be a positive integer."); + throw new BadRequestException(message, responseMediaType); + } + + CertificateManagementService certificateService = MDMAPIUtils.getCertificateManagementService(); + PaginationRequest paginationRequest = new PaginationRequest(startIndex, length); + try { + PaginationResult certificates = certificateService.getAllCertificates(paginationRequest); + return Response.status(Response.Status.OK).entity(certificates).type(responseMediaType).build(); + } catch (CertificateManagementDAOException e) { + String msg = "Error occurred while fetching all certificates."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + } + + @DELETE + @Path("{serialNumber}") + public Response removeCertificate(@HeaderParam("Accept") String acceptHeader, + @PathParam("serialNumber") String serialNumber) throws MDMAPIException { + MediaType responseMediaType = MDMAPIUtils.getResponseMediaType(acceptHeader); + Message message = new Message(); + + if (serialNumber == null || serialNumber.isEmpty()) { + message.setErrorMessage("Invalid serial number"); + message.setDiscription("Serial number is missing or invalid."); + throw new BadRequestException(message, responseMediaType); + } + + CertificateManagementService certificateService = MDMAPIUtils.getCertificateManagementService(); + boolean deleted; + try { + deleted = certificateService.removeCertificate(serialNumber); + if(deleted){ + return Response.status(Response.Status.OK).entity(true).type(responseMediaType).build(); + } else { + return Response.status(Response.Status.GONE).entity(false).type(responseMediaType).build(); + } + } catch (CertificateManagementDAOException e) { + String msg = "Error occurred while converting PEM file to X509Certificate"; + log.error(msg, e); + return Response.serverError().build(); + } + } +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java index 8acf4efe9..6fd806f33 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java @@ -21,16 +21,20 @@ package org.wso2.carbon.mdm.api; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; import org.wso2.carbon.mdm.api.common.MDMAPIException; import org.wso2.carbon.mdm.api.util.MDMAPIUtils; import org.wso2.carbon.mdm.api.util.MDMAppConstants; import org.wso2.carbon.mdm.api.util.ResponsePayload; +import org.wso2.carbon.policy.mgt.core.util.PolicyManagerUtil; import javax.jws.WebService; import javax.ws.rs.*; import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.List; /** * General Tenant Configuration REST-API implementation. @@ -67,8 +71,19 @@ public class Configuration { public TenantConfiguration getConfiguration() throws MDMAPIException { String msg; try { - return MDMAPIUtils.getTenantConfigurationManagementService().getConfiguration(MDMAppConstants. - RegistryConstants.GENERAL_CONFIG_RESOURCE_PATH); + TenantConfiguration tenantConfiguration = MDMAPIUtils.getTenantConfigurationManagementService(). + getConfiguration(MDMAppConstants.RegistryConstants.GENERAL_CONFIG_RESOURCE_PATH); + ConfigurationEntry configurationEntry = new ConfigurationEntry(); + configurationEntry.setContentType("text"); + configurationEntry.setName("notifierFrequency"); + configurationEntry.setValue(PolicyManagerUtil.getMonitoringFequency()); + List configList = tenantConfiguration.getConfiguration(); + if (configList == null) { + configList = new ArrayList<>(); + } + configList.add(configurationEntry); + tenantConfiguration.setConfiguration(configList); + return tenantConfiguration; } catch (ConfigurationManagementException e) { msg = "Error occurred while retrieving the tenant configuration."; log.error(msg, e); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java index a775318dd..84e88c92a 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Operation.java @@ -54,7 +54,7 @@ import java.util.List; public class Operation { private static Log log = LogFactory.getLog(Operation.class); - + /* @deprecated */ @GET public List getAllOperations() throws MDMAPIException { @@ -115,6 +115,7 @@ public class Operation { return operations; } + /* @deprecated */ @POST public ResponsePayload addOperation(DeviceOperationContext operationContext) throws MDMAPIException { DeviceManagementProviderService dmService; @@ -182,6 +183,8 @@ public class Operation { } appManagerConnector.installApplicationForDevices(operation, applicationWrapper.getDeviceIdentifiers()); } + Response.status(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Application installation request has been sent to the device."); return responseMsg; } catch (ApplicationManagementException e) { String msg = "Error occurred while saving the operation"; @@ -215,6 +218,8 @@ public class Operation { } appManagerConnector.installApplicationForDevices(operation, applicationWrapper.getDeviceIdentifiers()); } + Response.status(HttpStatus.SC_CREATED); + responseMsg.setMessageFromServer("Application removal request has been sent to the device."); return responseMsg; } catch (ApplicationManagementException e) { String msg = "Error occurred while saving the operation"; diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java index dea04d31b..c0dd24d14 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Policy.java @@ -173,24 +173,6 @@ public class Policy { @Path("{id}") public ResponsePayload updatePolicy(PolicyWrapper policyWrapper, @PathParam("id") int policyId) throws MDMAPIException { -// PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); -// ResponsePayload responseMsg = new ResponsePayload(); -// try { -// PolicyAdministratorPoint pap = policyManagementService.getPAP(); -// org.wso2.carbon.policy.mgt.common.Policy previousPolicy = pap.getPolicy(policyId); -// policy.setProfile(pap.getProfile(previousPolicy.getProfileId())); -// policy.setId(previousPolicy.getId()); -// pap.updatePolicy(policy); -// Response.status(HttpStatus.SC_OK); -// responseMsg.setMessageFromServer("Policy has been updated successfully."); -// return responseMsg; -// } catch (PolicyManagementException e) { -// String error = "Policy Management related exception"; -// log.error(error, e); -// throw new MDMAPIException(error, e); -// } - - PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); ResponsePayload responseMsg = new ResponsePayload(); @@ -205,16 +187,12 @@ public class Policy { policy.setUsers(policyWrapper.getUsers()); policy.setTenantId(policyWrapper.getTenantId()); policy.setCompliance(policyWrapper.getCompliance()); - // policy.setActive(true); try { PolicyAdministratorPoint pap = policyManagementService.getPAP(); -// pap.addPolicy(policy); pap.updatePolicy(policy); -// Response.status(HttpStatus.SC_CREATED); Response.status(HttpStatus.SC_OK); responseMsg.setStatusCode(HttpStatus.SC_CREATED); -// responseMsg.setMessageFromServer("Policy has been added successfully."); responseMsg.setMessageFromServer("Policy has been updated successfully."); return responseMsg; } catch (PolicyManagementException e) { @@ -293,23 +271,6 @@ public class Policy { } } -// @GET -// @Path("task/{mf}") -// public int taskService(@PathParam("mf") int monitoringFrequency) throws MDMAPIException { -// int policyCount = 0; -// PolicyManagerService policyManagementService = MDMAPIUtils.getPolicyManagementService(); -// try { -// TaskScheduleService taskScheduleService = policyManagementService.getTaskScheduleService(); -// taskScheduleService.startTask(monitoringFrequency); -// return policyCount; -// } catch (PolicyMonitoringTaskException e) { -// String error = "Policy Management related exception"; -// log.error(error, e); -// throw new MDMAPIException(error, e); -// } -// } - - @PUT @Produces("application/json") @Path("activate") @@ -333,7 +294,6 @@ public class Policy { } - @PUT @Produces("application/json") @Path("inactivate") @@ -356,7 +316,6 @@ public class Policy { return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } - @PUT @Produces("application/json") @Path("apply-changes") @@ -400,7 +359,6 @@ public class Policy { return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } - @GET @Path("update-task/{milliseconds}") public Response updateTaskService(@PathParam("milliseconds") int monitoringFrequency) throws MDMAPIException { @@ -421,7 +379,6 @@ public class Policy { return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } - @GET @Path("stop-task") public Response stopTaskService() throws MDMAPIException { @@ -442,7 +399,6 @@ public class Policy { return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } - @GET @Path("{type}/{id}") public ComplianceData getComplianceDataOfDevice(@PathParam("type") String type, @PathParam("id") String id) throws diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java index a0adeed6a..dda4f243f 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java @@ -419,4 +419,36 @@ public class Role { } return list; } + + /** + * This method is used to retrieve the role count of the system. + * + * @return returns the count. + * @throws MDMAPIException + */ + @GET + @Path("count") + public int getRoleCount() throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + String[] roles; + try { + if (log.isDebugEnabled()) { + log.debug("Getting the list of user roles"); + } + roles = userStoreManager.getRoleNames(); + + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving the list of user roles."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + // removing all internal roles and roles created for Service-providers + List filteredRoles = new ArrayList(); + for (String role : roles) { + if (!(role.startsWith("Internal/") || role.startsWith("Application/"))) { + filteredRoles.add(role); + } + } + return filteredRoles.size(); + } } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java index 16c9ee7ca..e1e065c1b 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/User.java @@ -25,10 +25,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.EmailMessageProperties; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.core.service.EmailMetaInfo; import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.CredentialManagementResponseBuilder; import org.wso2.carbon.mdm.api.util.MDMAPIUtils; import org.wso2.carbon.mdm.api.util.ResponsePayload; import org.wso2.carbon.mdm.beans.UserCredentialWrapper; @@ -37,6 +38,7 @@ import org.wso2.carbon.mdm.util.Constants; import org.wso2.carbon.mdm.util.SetReferenceTransformer; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreManager; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -50,14 +52,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.TreeSet; +import java.util.*; /** * This class represents the JAX-RS services of User related functionality. @@ -65,7 +60,7 @@ import java.util.TreeSet; public class User { private static Log log = LogFactory.getLog(User.class); - private String ROLE_EVERYONE = "Internal/everyone"; + private static final String ROLE_EVERYONE = "Internal/everyone"; /** * Method to add user to emm-user-store. @@ -85,22 +80,22 @@ public class User { // if user already exists if (log.isDebugEnabled()) { log.debug("User by username: " + userWrapper.getUsername() + - " already exists. Therefore, request made to add user was refused."); + " already exists. Therefore, request made to add user was refused."); } // returning response with bad request state responsePayload.setStatusCode(HttpStatus.SC_CONFLICT); responsePayload. setMessageFromServer("User by username: " + userWrapper.getUsername() + - " already exists. Therefore, request made to add user was refused."); + " already exists. Therefore, request made to add user was refused."); return Response.status(HttpStatus.SC_CONFLICT).entity(responsePayload).build(); } else { String initialUserPassword = generateInitialUserPassword(); Map defaultUserClaims = buildDefaultUserClaims(userWrapper.getFirstname(), userWrapper.getLastname(), - userWrapper.getEmailAddress()); + userWrapper.getEmailAddress()); // calling addUser method of carbon user api userStoreManager.addUser(userWrapper.getUsername(), initialUserPassword, - userWrapper.getRoles(), defaultUserClaims, null); + userWrapper.getRoles(), defaultUserClaims, null); // invite newly added user to enroll device inviteNewlyAddedUserToEnrollDevice(userWrapper.getUsername(), initialUserPassword); // Outputting debug message upon successful addition of user @@ -110,17 +105,13 @@ public class User { // returning response with success state responsePayload.setStatusCode(HttpStatus.SC_CREATED); responsePayload.setMessageFromServer("User by username: " + userWrapper.getUsername() + - " was successfully added."); + " was successfully added."); return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); } } catch (UserStoreException e) { - String errorMsg = "Exception in trying to add user by username: " + userWrapper.getUsername(); - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); - } catch (DeviceManagementException e) { - String errorMsg = "Exception in trying to add user by username: " + userWrapper.getUsername(); - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + String msg = "Exception in trying to add user by username: " + userWrapper.getUsername(); + log.error(msg, e); + throw new MDMAPIException(msg, e); } } @@ -164,9 +155,9 @@ public class User { return Response.status(HttpStatus.SC_NOT_FOUND).entity(responsePayload).build(); } } catch (UserStoreException e) { - String errorMsg = "Exception in trying to retrieve user by username: " + username; - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + String msg = "Exception in trying to retrieve user by username: " + username; + log.error(msg, e); + throw new MDMAPIException(msg, e); } } @@ -188,12 +179,12 @@ public class User { if (userStoreManager.isExistingUser(userWrapper.getUsername())) { Map defaultUserClaims = buildDefaultUserClaims(userWrapper.getFirstname(), userWrapper.getLastname(), - userWrapper.getEmailAddress()); + userWrapper.getEmailAddress()); if (StringUtils.isNotEmpty(userWrapper.getPassword())) { // Decoding Base64 encoded password byte[] decodedBytes = Base64.decodeBase64(userWrapper.getPassword()); userStoreManager.updateCredentialByAdmin(userWrapper.getUsername(), - new String(decodedBytes, "UTF-8")); + new String(decodedBytes, "UTF-8")); log.debug("User credential of username: " + userWrapper.getUsername() + " has been changed"); } List listofFilteredRoles = getFilteredRoles(userStoreManager, userWrapper.getUsername()); @@ -204,16 +195,16 @@ public class User { The difference of roles in existingRolesSet and newRolesSet needed to be deleted new roles to add = newRolesSet - The intersection of roles in existingRolesSet and newRolesSet */ - final TreeSet existingRolesSet = new TreeSet(); + final TreeSet existingRolesSet = new TreeSet<>(); Collections.addAll(existingRolesSet, existingRoles); - final TreeSet newRolesSet = new TreeSet(); + final TreeSet newRolesSet = new TreeSet<>(); Collections.addAll(newRolesSet, userWrapper.getRoles()); existingRolesSet.removeAll(newRolesSet); // Now we have the roles to delete String[] rolesToDelete = existingRolesSet.toArray(new String[existingRolesSet.size()]); - List roles = new ArrayList(Arrays.asList(rolesToDelete)); + List roles = new ArrayList<>(Arrays.asList(rolesToDelete)); roles.remove(ROLE_EVERYONE); - rolesToDelete = roles.toArray(new String[0]); + rolesToDelete = new String[0]; // Clearing and re-initializing the set existingRolesSet.clear(); Collections.addAll(existingRolesSet, existingRoles); @@ -229,28 +220,24 @@ public class User { // returning response with success state responsePayload.setStatusCode(HttpStatus.SC_CREATED); responsePayload.setMessageFromServer("User by username: " + userWrapper.getUsername() + - " was successfully updated."); + " was successfully updated."); return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); } else { if (log.isDebugEnabled()) { log.debug("User by username: " + userWrapper.getUsername() + - " doesn't exists. Therefore, request made to update user was refused."); + " doesn't exists. Therefore, request made to update user was refused."); } // returning response with bad request state responsePayload.setStatusCode(HttpStatus.SC_CONFLICT); responsePayload. setMessageFromServer("User by username: " + userWrapper.getUsername() + - " doesn't exists. Therefore, request made to update user was refused."); + " doesn't exists. Therefore, request made to update user was refused."); return Response.status(HttpStatus.SC_CONFLICT).entity(responsePayload).build(); } - } catch (UserStoreException e) { - String errorMsg = "Exception in trying to update user by username: " + userWrapper.getUsername(); - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); - } catch (UnsupportedEncodingException e) { - String errorMsg = "Exception in trying to update user by username: " + userWrapper.getUsername(); - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + } catch (UserStoreException | UnsupportedEncodingException e) { + String msg = "Exception in trying to update user by username: " + userWrapper.getUsername(); + log.error(msg, e); + throw new MDMAPIException(msg, e); } } @@ -270,7 +257,7 @@ public class User { Random randomGenerator = new Random(); String totalCharset = lowerCaseCharset + upperCaseCharset + numericCharset; int totalCharsetLength = totalCharset.length(); - StringBuffer initialUserPassword = new StringBuffer(); + StringBuilder initialUserPassword = new StringBuilder(); for (int i = 0; i < passwordLength; i++) { initialUserPassword .append(totalCharset.charAt(randomGenerator.nextInt(totalCharsetLength))); @@ -290,7 +277,7 @@ public class User { * @return {Object} Default user claims to be provided */ private Map buildDefaultUserClaims(String firstname, String lastname, String emailAddress) { - Map defaultUserClaims = new HashMap(); + Map defaultUserClaims = new HashMap<>(); defaultUserClaims.put(Constants.USER_CLAIM_FIRST_NAME, firstname); defaultUserClaims.put(Constants.USER_CLAIM_LAST_NAME, lastname); defaultUserClaims.put(Constants.USER_CLAIM_EMAIL_ADDRESS, emailAddress); @@ -337,24 +324,24 @@ public class User { return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); } } catch (UserStoreException e) { - String errorMsg = "Exception in trying to remove user by username: " + username; - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + String msg = "Exception in trying to remove user by username: " + username; + log.error(msg, e); + throw new MDMAPIException(msg, e); } } /** * get all the roles except for the internal/xxx and application/xxx * - * @param userStoreManager - * @param username + * @param userStoreManager User Store Manager associated with the currently logged in user + * @param username Username of the currently logged in user * @return the list of filtered roles * @throws UserStoreException */ private List getFilteredRoles(UserStoreManager userStoreManager, String username) throws UserStoreException { String[] roleListOfUser = userStoreManager.getRoleListOfUser(username); - List filteredRoles = new ArrayList(); + List filteredRoles = new ArrayList<>(); for (String role : roleListOfUser) { if (!(role.startsWith("Internal/") || role.startsWith("Application/"))) { filteredRoles.add(role); @@ -400,9 +387,9 @@ public class User { return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); } } catch (UserStoreException e) { - String errorMsg = "Exception in trying to retrieve roles for user by username: " + username; - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + String msg = "Exception in trying to retrieve roles for user by username: " + username; + log.error(msg, e); + throw new MDMAPIException(msg, e); } } @@ -419,10 +406,10 @@ public class User { log.debug("Getting the list of users with all user-related information"); } UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); - ArrayList userList; + List userList; try { String[] users = userStoreManager.listUsers("*", -1); - userList = new ArrayList(users.length); + userList = new ArrayList<>(users.length); UserWrapper user; for (String username : users) { user = new UserWrapper(); @@ -439,12 +426,10 @@ public class User { } ResponsePayload responsePayload = new ResponsePayload(); responsePayload.setStatusCode(HttpStatus.SC_OK); - int count = 0; - if (userList != null) { - count = userList.size(); - } + int count; + count = userList.size(); responsePayload.setMessageFromServer("All users were successfully retrieved. " + - "Obtained user count: " + count); + "Obtained user count: " + count); responsePayload.setResponseContent(userList); return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } @@ -463,10 +448,10 @@ public class User { log.debug("Getting the list of users with all user-related information using the filter : " + filter); } UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); - ArrayList userList; + List userList; try { String[] users = userStoreManager.listUsers(filter + "*", -1); - userList = new ArrayList(users.length); + userList = new ArrayList<>(users.length); UserWrapper user; for (String username : users) { user = new UserWrapper(); @@ -483,12 +468,10 @@ public class User { } ResponsePayload responsePayload = new ResponsePayload(); responsePayload.setStatusCode(HttpStatus.SC_OK); - int count = 0; - if (userList != null) { - count = userList.size(); - } + int count; + count = userList.size(); responsePayload.setMessageFromServer("All users were successfully retrieved. " + - "Obtained user count: " + count); + "Obtained user count: " + count); responsePayload.setResponseContent(userList); return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } @@ -506,10 +489,10 @@ public class User { log.debug("Getting the list of users by name"); } UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); - ArrayList userList; + List userList; try { String[] users = userStoreManager.listUsers("*" + userName + "*", -1); - userList = new ArrayList(users.length); + userList = new ArrayList<>(users.length); UserWrapper user; for (String username : users) { user = new UserWrapper(); @@ -526,12 +509,10 @@ public class User { } ResponsePayload responsePayload = new ResponsePayload(); responsePayload.setStatusCode(HttpStatus.SC_OK); - int count = 0; - if (userList != null) { - count = userList.size(); - } + int count; + count = userList.size(); responsePayload.setMessageFromServer("All users by username were successfully retrieved. " + - "Obtained user count: " + count); + "Obtained user count: " + count); responsePayload.setResponseContent(userList); return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } @@ -549,14 +530,11 @@ public class User { log.debug("Getting the list of users by name"); } UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); - ArrayList userList; + List userList; try { String[] users = userStoreManager.listUsers("*" + userName + "*", -1); - userList = new ArrayList(users.length); - UserWrapper user; - for (String username : users) { - userList.add(username); - } + userList = new ArrayList<>(users.length); + Collections.addAll(userList, users); } catch (UserStoreException e) { String msg = "Error occurred while retrieving the list of users"; log.error(msg, e); @@ -564,12 +542,10 @@ public class User { } ResponsePayload responsePayload = new ResponsePayload(); responsePayload.setStatusCode(HttpStatus.SC_OK); - int count = 0; - if (userList != null) { - count = userList.size(); - } + int count; + count = userList.size(); responsePayload.setMessageFromServer("All users by username were successfully retrieved. " + - "Obtained user count: " + count); + "Obtained user count: " + count); responsePayload.setResponseContent(userList); return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); } @@ -582,9 +558,14 @@ public class User { * @return A list of usernames * @throws MDMAPIException, UserStoreException */ - private String getClaimValue(String username, String claimUri) throws MDMAPIException, UserStoreException { + private String getClaimValue(String username, String claimUri) throws MDMAPIException { UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); - return userStoreManager.getUserClaimValue(username, claimUri, null); + try { + return userStoreManager.getUserClaimValue(username, claimUri, null); + } catch (UserStoreException e) { + throw new MDMAPIException("Error occurred while retrieving value assigned to the claim '" + + claimUri + "'", e); + } } /** @@ -593,31 +574,37 @@ public class User { * @param username Username of the user * @throws MDMAPIException, UserStoreException, DeviceManagementException */ - private void inviteNewlyAddedUserToEnrollDevice(String username, String password) throws - MDMAPIException, - UserStoreException, - DeviceManagementException { + private void inviteNewlyAddedUserToEnrollDevice( + String username, String password) throws MDMAPIException { if (log.isDebugEnabled()) { log.debug("Sending invitation mail to user by username: " + username); } - String tennentDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); - if (tennentDomain.equalsIgnoreCase("carbon.super")) { - tennentDomain = ""; + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(tenantDomain)) { + tenantDomain = ""; } if (!username.contains("/")) { username = "/" + username; } String[] usernameBits = username.split("/"); DeviceManagementProviderService deviceManagementProviderService = MDMAPIUtils.getDeviceManagementService(); - EmailMessageProperties emailMessageProperties = new EmailMessageProperties(); - emailMessageProperties.setUserName(usernameBits[1]); - emailMessageProperties.setDomainName(tennentDomain); - emailMessageProperties.setFirstName(getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); - emailMessageProperties.setPassword(password); - String[] mailAddress = new String[1]; - mailAddress[0] = getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS); - emailMessageProperties.setMailTo(mailAddress); - deviceManagementProviderService.sendRegistrationEmail(emailMessageProperties); + + Properties props = new Properties(); + props.setProperty("username", usernameBits[1]); + props.setProperty("domain-name", tenantDomain); + props.setProperty("first-name", getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + props.setProperty("password", password); + + String recipient = getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS); + + EmailMetaInfo metaInfo = new EmailMetaInfo(recipient, props); + try { + deviceManagementProviderService.sendRegistrationEmail(metaInfo); + } catch (DeviceManagementException e) { + String msg = "Error occurred while sending registration email to user '" + username + "'"; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } } /** @@ -635,26 +622,20 @@ public class User { } DeviceManagementProviderService deviceManagementProviderService = MDMAPIUtils.getDeviceManagementService(); try { - for (int i = 0; i < usernames.size(); i++) { - EmailMessageProperties emailMessageProperties = new EmailMessageProperties(); - emailMessageProperties - .setFirstName(getClaimValue(usernames.get(i), Constants.USER_CLAIM_FIRST_NAME)); - emailMessageProperties.setUserName(usernames.get(i)); - String[] mailAddress = new String[1]; - mailAddress[0] = getClaimValue(usernames.get(i), Constants.USER_CLAIM_EMAIL_ADDRESS); - if (StringUtils.isNotEmpty(mailAddress[0])) { - emailMessageProperties.setMailTo(mailAddress); - deviceManagementProviderService.sendEnrolmentInvitation(emailMessageProperties); - } + for (String username : usernames) { + String recipient = getClaimValue(username, Constants.USER_CLAIM_EMAIL_ADDRESS); + + Properties props = new Properties(); + props.setProperty("first-name", getClaimValue(username, Constants.USER_CLAIM_FIRST_NAME)); + props.setProperty("username", username); + + EmailMetaInfo metaInfo = new EmailMetaInfo(recipient, props); + deviceManagementProviderService.sendEnrolmentInvitation(metaInfo); } - } catch (UserStoreException e) { - String errorMsg = "Exception in trying to invite user."; - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); } catch (DeviceManagementException e) { - String errorMsg = "Exception in trying to invite user."; - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + String msg = "Error occurred while inviting user to enrol their device"; + log.error(msg, e); + throw new MDMAPIException(msg, e); } ResponsePayload responsePayload = new ResponsePayload(); responsePayload.setStatusCode(HttpStatus.SC_OK); @@ -685,9 +666,9 @@ public class User { } return dmService.getDevicesOfUser(username); } catch (DeviceManagementException e) { - String errorMsg = "Device management error"; - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); + String msg = "Device management error"; + log.error(msg, e); + throw new MDMAPIException(msg, e); } } @@ -734,7 +715,7 @@ public class User { } SetReferenceTransformer transformer = new SetReferenceTransformer(); transformer.transform(Arrays.asList(userStoreManager.getRoleListOfUser(username)), - userList); + userList); final String[] rolesToAdd = (String[]) transformer.getObjectsToAdd().toArray(new String[transformer.getObjectsToAdd().size()]); final String[] rolesToDelete = (String[]) @@ -757,30 +738,26 @@ public class User { * @throws MDMAPIException */ @POST - @Path("reset-password") + @Path("change-password") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) public Response resetPassword(UserCredentialWrapper credentials) throws MDMAPIException { - UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); - ResponsePayload responsePayload = new ResponsePayload(); - try { - byte[] decodedNewPassword = Base64.decodeBase64(credentials.getNewPassword()); - userStoreManager.updateCredentialByAdmin(credentials.getUsername(), new String( - decodedNewPassword, "UTF-8")); - responsePayload.setStatusCode(HttpStatus.SC_CREATED); - responsePayload.setMessageFromServer("User password by username: " + credentials.getUsername() + - " was successfully changed."); - return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); - } catch (UserStoreException e) { - String errorMsg = "Exception in trying to change the password by username: " + credentials.getUsername(); - log.error(errorMsg, e); - responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); - responsePayload.setMessageFromServer("Old password does not match."); - return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); - } catch (UnsupportedEncodingException e) { - String errorMsg = "Exception in trying to change the password by username: " + credentials.getUsername(); - log.error(errorMsg, e); - throw new MDMAPIException(errorMsg, e); - } + return CredentialManagementResponseBuilder.buildChangePasswordResponse(credentials); } -} + + /** + * Method to change the user password. + * + * @param credentials Wrapper object representing user credentials. + * @return {Response} Status of the request wrapped inside Response object. + * @throws MDMAPIException + */ + @POST + @Path("reset-password") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response resetPasswordByAdmin(UserCredentialWrapper credentials) throws MDMAPIException { + return CredentialManagementResponseBuilder.buildResetPasswordResponse(credentials); + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/CredentialManagementResponseBuilder.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/CredentialManagementResponseBuilder.java new file mode 100644 index 000000000..640036758 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/CredentialManagementResponseBuilder.java @@ -0,0 +1,105 @@ +/* + * 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.wso2.carbon.mdm.api.util; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.beans.UserCredentialWrapper; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.api.UserStoreManager; + +import javax.ws.rs.core.Response; +import java.io.UnsupportedEncodingException; + +/** + * This class builds Credential modification related Responses + */ +public class CredentialManagementResponseBuilder { + + private static Log log = LogFactory.getLog(CredentialManagementResponseBuilder.class); + + private ResponsePayload responsePayload; + + /** + * Builds the response to change the password of a user + * @param credentials - User credentials + * @return Response Object + * @throws MDMAPIException + */ + public static Response buildChangePasswordResponse(UserCredentialWrapper credentials) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + + try { + byte[] decodedNewPassword = Base64.decodeBase64(credentials.getNewPassword()); + byte[] decodedOldPassword = Base64.decodeBase64(credentials.getOldPassword()); + userStoreManager.updateCredential(credentials.getUsername(), new String( + decodedNewPassword, "UTF-8"), new String(decodedOldPassword, "UTF-8")); + responsePayload.setStatusCode(HttpStatus.SC_CREATED); + responsePayload.setMessageFromServer("User password by username: " + credentials.getUsername() + + " was successfully changed."); + return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); + } catch (UserStoreException e) { + log.error(e.getMessage(), e); + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer("Old password does not match."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } catch (UnsupportedEncodingException e) { + String errorMsg = "Could not change the password of the user: " + credentials.getUsername() + + ". The Character Encoding is not supported."; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + + } + + /** + * Builds the response to reset the password of a user + * @param credentials - User credentials + * @return Response Object + * @throws MDMAPIException + */ + public static Response buildResetPasswordResponse(UserCredentialWrapper credentials) throws MDMAPIException { + UserStoreManager userStoreManager = MDMAPIUtils.getUserStoreManager(); + ResponsePayload responsePayload = new ResponsePayload(); + try { + byte[] decodedNewPassword = Base64.decodeBase64(credentials.getNewPassword()); + userStoreManager.updateCredentialByAdmin(credentials.getUsername(), new String( + decodedNewPassword, "UTF-8")); + responsePayload.setStatusCode(HttpStatus.SC_CREATED); + responsePayload.setMessageFromServer("User password by username: " + credentials.getUsername() + + " was successfully changed."); + return Response.status(HttpStatus.SC_CREATED).entity(responsePayload).build(); + } catch (UserStoreException e) { + log.error(e.getMessage(), e); + responsePayload.setStatusCode(HttpStatus.SC_BAD_REQUEST); + responsePayload.setMessageFromServer("Could not change the password."); + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(responsePayload).build(); + } catch (UnsupportedEncodingException e) { + String errorMsg = "Could not change the password of the user: " + credentials.getUsername() + + ". The Character Encoding is not supported."; + log.error(errorMsg, e); + throw new MDMAPIException(errorMsg, e); + } + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java index 0c474818a..6b7cbab59 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java @@ -20,6 +20,7 @@ package org.wso2.carbon.mdm.api.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.certificate.mgt.core.service.CertificateManagementService; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; @@ -43,6 +44,7 @@ import org.wso2.carbon.user.api.UserStoreManager; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; +import javax.ws.rs.core.MediaType; import java.util.List; /** @@ -51,6 +53,7 @@ import java.util.List; public class MDMAPIUtils { private static final String NOTIFIER_FREQUENCY = "notifierFrequency"; + public static final MediaType DEFAULT_CONTENT_TYPE = MediaType.APPLICATION_JSON_TYPE; private static Log log = LogFactory.getLog(MDMAPIUtils.class); @@ -252,4 +255,31 @@ public class MDMAPIUtils { pagingResponse.setData(data); return pagingResponse; } + + public static CertificateManagementService getCertificateManagementService() { + + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + CertificateManagementService certificateManagementService = (CertificateManagementService) + ctx.getOSGiService(CertificateManagementService.class, null); + + if (certificateManagementService == null) { + String msg = "Certificate Management service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + + return certificateManagementService; + } + + + public static MediaType getResponseMediaType(String acceptHeader) { + MediaType responseMediaType; + if (acceptHeader == null || MediaType.WILDCARD.equals(acceptHeader)) { + responseMediaType = DEFAULT_CONTENT_TYPE; + } else { + responseMediaType = MediaType.valueOf(acceptHeader); + } + + return responseMediaType; + } } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/EnrollmentCertificate.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/EnrollmentCertificate.java new file mode 100644 index 000000000..bde1cf1a7 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/EnrollmentCertificate.java @@ -0,0 +1,50 @@ +/* + * 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.wso2.carbon.mdm.beans; + +public class EnrollmentCertificate { + String serial; + String pem; + int tenantId; + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + + public String getSerial() { + return serial; + } + + public void setSerial(String serial) { + this.serial = serial; + } + + public String getPem() { + return pem; + } + + public void setPem(String pem) { + this.pem = pem; + } + +} diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java index 0e4778d23..acdb9efca 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/beans/UserWrapper.java @@ -1,17 +1,17 @@ /* - * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * 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 + * 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 + * "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. */ @@ -84,4 +84,4 @@ public class UserWrapper { public void setPassword(String password) { this.password = password; } -} +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/BadRequestException.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/BadRequestException.java new file mode 100644 index 000000000..adbe78069 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/BadRequestException.java @@ -0,0 +1,31 @@ +/* + * 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.wso2.carbon.mdm.exception; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +public class BadRequestException extends WebApplicationException { + + public BadRequestException(Message message, MediaType mediaType) { + super(Response.status(Response.Status.BAD_REQUEST).entity(message).type(mediaType).build()); + } + +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/Message.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/Message.java new file mode 100644 index 000000000..4d5ee2ded --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/exception/Message.java @@ -0,0 +1,41 @@ +/* + * 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.wso2.carbon.mdm.exception; + +public class Message { + + private String errorMessage; + private String discription; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getDiscription() { + return discription; + } + + public void setDiscription(String discription) { + this.discription = discription; + } +} \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml index 0e11fe9ba..0d5ae5347 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml @@ -30,165 +30,305 @@ + + + Device Management + /device-mgt + / + GET + + + + Device Management Admin + /device-mgt/emm-admin + / + GET + + + + Device Management User + /device-mgt/user + / + GET + + + + Devices + /device-mgt/emm-admin/devices + / + GET + + + + Policies + /device-mgt/emm-admin/policies + / + GET + + + + Notifications + /device-mgt/emm-admin/notifications + / + GET + + + + Users + /device-mgt/emm-admin/users + / + GET + + + + Operations + /device-mgt/emm-admin/operations + / + GET + + + + Applications + /device-mgt/emm-admin/operations/applications + / + GET + + - Get all devices - /device-mgt/devices/list + Roles + /device-mgt/emm-admin/roles + / + GET + + + + Configurations + /device-mgt/emm-admin/platform-configs + / + GET + + + + View Dashboard + /device-mgt/emm-admin/dashboard + / + GET + + + + List devices + /device-mgt/emm-admin/devices/list /devices GET - emm_admin - Get all device types - /device-mgt/devices/types + List devices + /device-mgt/emm-admin/devices/list + /devices/types + GET + + + + Add policy + /device-mgt/emm-admin/policies/add + /devices/types + GET + + + + Edit policy + /device-mgt/emm-admin/policies/update /devices/types GET - emm_admin View device - /device-mgt/devices/view + /device-mgt/emm-admin/devices/view /devices/view GET - emm_admin - Get device - /device-mgt/devices/view - /devices/*/* + View device + /device-mgt/user/devices/view + /devices/view GET - emm_admin,emm_user + + + + + + + + - Get users' devices - /device-mgt/devices/view + View device + /device-mgt/emm-admin/devices/view /devices/user/*/* GET - emm_admin,emm_user - Get device count - /device-mgt/devices/count + List devices + /device-mgt/emm-admin/devices/list /devices/count GET - emm_admin - Get all users' devices - /device-mgt/devices/list + List devices + /device-mgt/emm-admin/devices/list /devices/name/*/* GET - emm_admin,emm_user - Get all notifications - /device-mgt/notifications/view + View notifications + /device-mgt/emm-admin/notifications/view /notifications GET - emm_admin Add notification - /device-mgt/notifications/add + /device-mgt/emm-admin/notifications/add /notifications POST - emm_admin Update notification - /device-mgt/notifications/view + /device-mgt/emm-admin/notifications/update /notifications/*/* PUT - emm_admin - Get new notifications - /device-mgt/notifications/view + View notifications + /device-mgt/emm-admin/notifications/view /notifications/* GET - emm_admin - Get all operations - /device-mgt/operations/view + View user + /device-mgt/emm-admin/users/view /operations GET - emm_admin - Add Operation - /device-mgt/operations/add + Install application + /device-mgt/emm-admin/operations/applications/install-applications /operations POST - emm_admin - Install Application - /device-mgt/operations/application/install + Install application + /device-mgt/emm-admin/operations/applications/install-applications /operations/installApp/* POST - emm_admin,emm_user - Uninstall Application - /device-mgt/operations/application/uninstall + Uninstall application + /device-mgt/emm-admin/operations/applications/uninstall-applications /operations/uninstallApp/* POST - emm_admin,emm_user - Get Applications For Devices - /device-mgt/operations/application/view + View application + /device-mgt/emm-admin/operations/applications/view-applications /operations/*/*/* GET - emm_admin,emm_user + - Get Device Operations - /device-mgt/operations/view + View devices + /device-mgt/user/devices/view + /operations/*/*/* + GET + + + + View device + /device-mgt/emm-admin/devices/view + /operations/*/*/* + GET + + + + View device + /device-mgt/emm-admin/devices/view /operations/*/* GET - emm_admin,emm_user - Get Applications For Device Type - /device-mgt/operations/application/view - /operations/* + View device + /device-mgt/emm-admin/devices/view + /operations/paginate/*/* + GET + + + + View device + /device-mgt/user/devices/view + /operations/*/* GET - emm_admin,emm_user + + + View device + /device-mgt/user/devices/view + /operations/paginate/*/* + GET + + + + + + + + + - Get features - /device-mgt/features/view + List policies + /device-mgt/emm-admin/policies/list /features/* GET - emm_admin + - Get all features - /device-mgt/features/view + View device + /device-mgt/emm-admin/devices/view + /features/* + GET + + + + View device + /device-mgt/user/devices/view + /features/* + GET + + + + View device + /device-mgt/user/devices/view /features GET emm_admin @@ -197,328 +337,438 @@ - Get all roles - /device-mgt/roles + List roles + /device-mgt/emm-admin/roles/list /roles GET - emm_admin + - Get role permissions - /device-mgt/roles - /roles/permissions + View user + /device-mgt/emm-admin/users/view + /roles GET - emm_admin + - Get User roles - /device-mgt/roles - /roles/* + Add policy + /device-mgt/emm-admin/policies/add + /roles GET - emm_admin + - Update User roles - /device-mgt/roles/update + Update policy + /device-mgt/emm-admin/policies/update /roles - PUT - emm_admin + GET + + + + List roles + /device-mgt/emm-admin/roles/list + /roles/permissions + GET + - Update a specific role - /device-mgt/roles/update + List roles + /device-mgt/emm-admin/roles/list /roles/* + GET + + + + Add user + /device-mgt/emm-admin/users/add + /roles/* + GET + + + + Update role + /device-mgt/emm-admin/roles/update + /roles PUT - emm_admin + + + + + + + + + - Update User roles - /device-mgt/roles - /roles/*/users + Update role + /device-mgt/emm-admin/roles/update + /roles/users PUT - emm_admin + - Save User roles - /device-mgt/roles/add + Add role + /device-mgt/emm-admin/roles/add /roles POST - emm_admin + - Delete User roles - /device-mgt/roles/delete + Remove role + /device-mgt/emm-admin/roles/remove /roles DELETE - emm_admin + + + + List roles + /device-mgt/emm-admin/roles/list + /roles/count + GET - Get all users - /device-mgt/users/view + List users + /device-mgt/emm-admin/users/list /users GET - emm_admin + Add user - /device-mgt/users/add + /device-mgt/emm-admin/users/add /users POST - emm_admin + - Get user - /device-mgt/users/view + View user + /device-mgt/emm-admin/users/view /users/view GET - emm_admin + Update user - /device-mgt/users/update + /device-mgt/emm-admin/users/update /users PUT - emm_admin + Change user password - /device-mgt/users/reset-password - /users/reset-password + /login + /users/change-password POST emm_admin + + + Reset password + /device-mgt/emm-admin/users/password-reset + /users/reset-password + POST + + - Delete user - /device-mgt/users/delete + Remove user + /device-mgt/emm-admin/users/remove /users DELETE - emm_admin + - Get user roles by name - /device-mgt/users/roles + View user + /device-mgt/emm-admin/users/view /users/roles GET - emm_admin + + + + + + + + - Get user roles by name - /device-mgt/users/roles + Add user + /device-mgt/emm-admin/users/add /roles - GET - emm_admin + POST + - Save Roles - /device-mgt/users/roles - /roles - POST - emm_admin + List devices + /device-mgt/user/devices/list + /users/devices + GET + - Get all devices of user - /device-mgt/users/devices + List devices + /device-mgt/emm-admin/devices/list /users/devices GET - emm_admin + - Get user roles - /device-mgt/users/roles + View user + /device-mgt/emm-admin/users/view /users/*/* GET - emm_admin + - Get user count - /device-mgt/users/view + List users + /device-mgt/emm-admin/users/list /users/count GET - emm_admin + - Get all user names - /device-mgt/users/view + List users + /device-mgt/emm-admin/users/list + /users/view-users + GET + + + + Add role + /device-mgt/emm-admin/roles/add + /users/view-users + GET + + + + Update role + /device-mgt/emm-admin/roles/update /users/view-users GET - emm_admin + - Get all usernames - /device-mgt/users/view + Add policy + /device-mgt/emm-admin/policies/add + /users/view-users + GET + + + + Update policy + /device-mgt/emm-admin/policies/update + /users/view-users + GET + + + + List users + /device-mgt/emm-admin/users/list /users/users-by-username GET - emm_admin + - Get filtered usernames - /device-mgt/users/view + List users + /device-mgt/emm-admin/users/list /users/users-by-username/* GET - emm_admin + - Send invitation - /device-mgt/users/invite + Invite user + /device-mgt/emm-admin/users/invite /users/email-invitation POST - emm_admin + + + + Authorize user + /login + /users/authorize + POST Add Policy - /device-mgt/policies/add + /device-mgt/emm-admin/policies/add /policies/inactive-policy POST - emm_admin + - Get Policy For Device - /device-mgt/policies/view + List policies + /device-mgt/emm-admin/policies/list /policies/*/* POST - emm_admin + - Get Policy For Device By Type - /device-mgt/policies/view + List policies + /device-mgt/emm-admin/policies/list + /policies/*/*/* + GET + + + + View device + /device-mgt/emm-admin/devices/view + /policies/*/*/* + GET + + + + View device + /device-mgt/user/devices/view /policies/*/*/* GET - emm_admin + - Add Active Policy - /device-mgt/policies/add + Add policy + /device-mgt/emm-admin/policies/add /policies/active-policy POST - emm_admin + - Bulk Policy Removal - /device-mgt/policies/bulk-remove + Remove policy + /device-mgt/emm-admin/policies/remove /policies/bulk-remove POST - emm_admin + - Get Policies - /device-mgt/policies/view + List policies + /device-mgt/emm-admin/policies/list /policies GET - emm_admin + - Get Policy - /device-mgt/policies/view + List policies + /device-mgt/emm-admin/policies/list /policies/* GET - emm_admin + - Update Policy - /device-mgt/policies/update + Update policy + /device-mgt/emm-admin/policies/update /policies/* PUT - emm_admin + - Delete Policy - /device-mgt/policies/delete + Remove policy + /device-mgt/emm-admin/policies/remove /policies DELETE - emm_admin + - Policy Count - /device-mgt/policies/view + List policies + /device-mgt/emm-admin/policies/list /policies/count GET - emm_admin + - Policy priorities - /device-mgt/policies/update + Edit policy + /device-mgt/emm-admin/policies/update /policies/priorities PUT - emm_admin + - Activate Policy - /device-mgt/policies/update + Edit policy + /device-mgt/emm-admin/policies/update /policies/activate PUT - emm_admin + - Inactivate Policy - /device-mgt/policies/update + Add policy + /device-mgt/emm-admin/policies/add + /policies/activate + PUT + + + + Edit policy + /device-mgt/emm-admin/policies/update /policies/inactivate PUT - emm_admin + + + Add policy + /device-mgt/emm-admin/policies/add + /policies/inactivate + PUT + + - Apply Policy changes - /device-mgt/policies/update + Edit policy + /device-mgt/emm-admin/policies/update /policies/apply-changes PUT - emm_admin + - Start Task - /device-mgt/policies/task + Add policy + /device-mgt/emm-admin/policies/add /policies/start-task/* GET - emm_admin + - Update Task - /device-mgt/policies/task + Add policy + /device-mgt/emm-admin/policies/add /policies/update-task/* GET - emm_admin + - Stop Task - /device-mgt/policies/task + Add policy + /device-mgt/emm-admin/policies/add /policies/stop-task GET - emm_admin + - Get Policy Compliance - /device-mgt/policies/compliance + List policies + /device-mgt/emm-admin/policies/list /policies/*/* GET - emm_admin - Add profile - /device-mgt/profiles/add + Add policy + /device-mgt/emm-admin/policies/add /profiles POST - emm_admin + - Update profile - /device-mgt/profiles/update + Edit policy + /device-mgt/emm-admin/policies/update /profiles/* PUT - emm_admin + - Add profile - /device-mgt/profiles/delete + Remove policy + /device-mgt/emm-admin/policies/remove /profiles/* DELETE - emm_admin @@ -541,25 +791,49 @@ - Get configuration - /device-mgt/tenant/configuration/view + View configuration + /device-mgt/emm-admin/platform-configs/view /configuration GET - emm_admin + Add configuration - /device-mgt/tenant/configuration/modify + /device-mgt/emm-admin/platform-configs/add /configuration POST - emm_admin + Update configuration - /device-mgt/tenant/configuration/modify + /device-mgt/emm-admin/platform-configs/modify /configuration PUT - emm_admin + + + + + Save certificate in the database + /device-mgt/android/certificate/save + /certificates/saveCertificate + POST + emm_admin + + + get certificate in the database + /device-mgt/android/certificate/Get + /certificates/* + GET + emm_admin + + + get certificate in the database + /device-mgt/android/certificate/Get + /certificates/* + DELETE + emm_admin + + \ No newline at end of file diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml index dc53a029b..5db3ba522 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -1,6 +1,6 @@ @@ -105,6 +105,15 @@ + + + + + + + + + @@ -133,6 +142,7 @@ + diff --git a/components/mobile-plugins/mobile-base-plugin/pom.xml b/components/mobile-plugins/mobile-base-plugin/pom.xml index 94ae0d56a..212c8f78b 100644 --- a/components/mobile-plugins/mobile-base-plugin/pom.xml +++ b/components/mobile-plugins/mobile-base-plugin/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -34,8 +34,8 @@ org.wso2.carbon.device.mgt.mobile - - + org.wso2.carbon.device.mgt.mobile.api + org.wso2.carbon.device.mgt.mobile.ui org.wso2.carbon.device.mgt.mobile.url.printer diff --git a/components/mobile-plugins/pom.xml b/components/mobile-plugins/pom.xml index 898aded05..fd8749a3e 100644 --- a/components/mobile-plugins/pom.xml +++ b/components/mobile-plugins/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -33,8 +33,8 @@ http://wso2.org - - + android-plugin + windows-plugin mobile-base-plugin diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java deleted file mode 100644 index df5d15392..000000000 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/discovery/beans/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* -* Copyright (c) 2015, 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. -*/ - -@javax.xml.bind.annotation.XmlSchema(namespace = - "http://schemas.microsoft.com/windows/management/2012/01/enrollment", - elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) -package org.wso2.carbon.mdm.mobileservices.windows.services.discovery.beans; diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java deleted file mode 100644 index 47dd02949..000000000 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/wstep/beans/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -@XmlSchema(namespace = "http://www.w3.org/2003/05/soap-envelope", - xmlns = { - @XmlNs(prefix = "", namespaceURI = "http://www.w3.org/2003/05/soap-envelope") - }, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) - -package org.wso2.carbon.mdm.mobileservices.windows.services.wstep.beans; - -import javax.xml.bind.annotation.XmlNs; -import javax.xml.bind.annotation.XmlSchema; \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java deleted file mode 100644 index f3c0f5b58..000000000 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/java/org/wso2/carbon/mdm/mobileservices/windows/services/xcep/beans/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -@javax.xml.bind.annotation.XmlSchema(namespace = "http://schemas.microsoft" + - ".com/windows/pki/2009/01/enrollmentpolicy", - elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) - -package org.wso2.carbon.mdm.mobileservices.windows.services.xcep.beans; diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml deleted file mode 100644 index 7df287f68..000000000 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/properties.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - Federated - wso2carbon - cacert - CN=mdmcn - 3 - 300 - wso2.com - \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/pom.xml similarity index 98% rename from components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml rename to components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/pom.xml index 8ee9a2c23..f5f7dcabd 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/pom.xml +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/pom.xml @@ -1,5 +1,5 @@ + + Federated + wso2carbon + cacert + CN=mdmcn + 3 + 300 + wso2.com + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/resources/wap-provisioning.xml similarity index 85% rename from components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml rename to components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/resources/wap-provisioning.xml index e6729e0f4..9a6561b45 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wap-provisioning.xml +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/resources/wap-provisioning.xml @@ -1,19 +1,19 @@ diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wso2mdm.jks b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/resources/wso2mdm.jks similarity index 100% rename from components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/resources/wso2mdm.jks rename to components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/resources/wso2mdm.jks diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/webapp/META-INF/permissions.xml similarity index 95% rename from components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml rename to components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/webapp/META-INF/permissions.xml index feb34b098..1a69d570d 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/permissions.xml +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/webapp/META-INF/permissions.xml @@ -1,18 +1,18 @@ diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/webapp/META-INF/webapp-classloading.xml similarity index 55% rename from components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml rename to components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/webapp/META-INF/webapp-classloading.xml index 0371f7c29..c90403cc6 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.agent/src/main/webapp/META-INF/webapp-classloading.xml +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.api/src/main/webapp/META-INF/webapp-classloading.xml @@ -1,21 +1,21 @@ + + + + + + + windows-plugin + org.wso2.carbon.devicemgt-plugins + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.windows.ui + 2.1.0-SNAPSHOT + WSO2 Carbon - Mobile Windows UI + pom + + + + + maven-assembly-plugin + 2.5.5 + + ${project.artifactId}-${carbon.device.mgt.version} + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/assembly/src.xml b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/assembly/src.xml new file mode 100644 index 000000000..2797034e0 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/devicemgt + / + true + + + \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.hbs b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.hbs new file mode 100644 index 000000000..cfdb0ed54 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.hbs @@ -0,0 +1,14 @@ +{{#zone "device-opetations"}} +
        + Operations +
        +
        + {{unit "mdm.unit.device.operation-bar"}} +
        +{{/zone}} + +{{#zone "bottomJs"}} + {{js "js/device-detail.js"}} + + {{js "js/load-map.js"}} +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.json b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/device-detail.js b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/device-detail.js new file mode 100644 index 000000000..aa2384fc3 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/device-detail.js @@ -0,0 +1,197 @@ +/* + * 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 () { + var deviceId = $(".device-id"); + var deviceIdentifier = deviceId.data("deviceid"); + var deviceType = deviceId.data("type"); + var payload = [deviceIdentifier]; + var operationTable; + if (deviceType == "ios") { + var serviceUrl = "/ios/operation/deviceinfo"; + } else if (deviceType == "android") { + var serviceUrl = "/mdm-android-agent/operation/device-info"; + } + if (serviceUrl) { + invokerUtil.post(serviceUrl, payload, + function (message) { + console.log(message); + }, function (message) { + console.log(message); + }); + } + $(document).ready(function () { + $(".panel-body").removeClass("hidden"); + $("#loading-content").remove(); + + loadOperationsLog(); + loadApplicationsList(); + loadPolicyCompliance(); + + $("#refresh-policy").click(function () { + $('#policy-spinner').removeClass('hidden'); + loadPolicyCompliance(); + }); + + $("#refresh-apps").click(function () { + $('#apps-spinner').removeClass('hidden'); + loadApplicationsList(); + }); + + $("#refresh-operations").click(function () { + $('#operations-spinner').removeClass('hidden'); + loadOperationsLog(true); + }); + loadOperationBar(deviceType); + }); + + function loadOperationsLog(update) { + var operationsLog = $("#operations-log"); + var deviceListingSrc = operationsLog.attr("src"); + var deviceId = operationsLog.data("device-id"); + var deviceType = operationsLog.data("device-type"); + + $.template("operations-log", deviceListingSrc, function (template) { + var serviceURL = "/devicemgt_admin/operations/" + deviceType + "/" + deviceId; + + var successCallback = function (data) { + data = JSON.parse(data); + $('#operations-spinner').addClass('hidden'); + var viewModel = {}; + viewModel.operations = data; + if (data.length > 0) { + var content = template(viewModel); + if (!update) { + $("#operations-log-container").html(content); + operationTable = $('#operations-log-table').datatables_extended(); + } else { + $('#operations-log-table').dataTable().fnClearTable(); + for (var i = 0; i < data.length; i++) { + var status; + if (data[i].status == "COMPLETED") { + status = " Completed"; + } else if (data[i].status == "PENDING") { + status = " Pending"; + } else if (data[i].status == "ERROR") { + status = " Error"; + } else if (data[i].status == "IN_PROGRESS") { + status = " In Progress"; + } + + $('#operations-log-table').dataTable().fnAddData([ + data[i].code, + status, + data[i].createdTimeStamp + ]); + } + } + } + + }; + invokerUtil.get(serviceURL, + successCallback, function (message) { + console.log(message); + }); + }); + + } + + function loadApplicationsList() { + var applicationsList = $("#applications-list"); + var deviceListingSrc = applicationsList.attr("src"); + var deviceId = applicationsList.data("device-id"); + var deviceType = applicationsList.data("device-type"); + + $.template("application-list", deviceListingSrc, function (template) { + var serviceURL = "/devicemgt_admin/operations/" + deviceType + "/" + deviceId + "/apps"; + + var successCallback = function (data) { + data = JSON.parse(data); + $('#apps-spinner').addClass('hidden'); + var viewModel = {}; + if (data != null && data.length > 0) { + for (var i = 0; i < data.length; i++) { + data[i].name = data[i].name.replace(/[^\w\s]/gi, ' '); + data[i].name = data[i].name.replace(/[0-9]/g, ' '); + } + } + viewModel.applications = data; + viewModel.deviceType = deviceType; + if (data.length > 0) { + var content = template(viewModel); + $("#applications-list-container").html(content); + } + + }; + invokerUtil.get(serviceURL, + successCallback, function (message) { + console.log(message); + }); + }); + } + + function loadPolicyCompliance() { + var policyCompliance = $("#policy-view"); + var policySrc = policyCompliance.attr("src"); + var deviceId = policyCompliance.data("device-id"); + var deviceType = policyCompliance.data("device-type"); + var activePolicy = null; + + $.template("policy-view", policySrc, function (template) { + var serviceURLPolicy = "/devicemgt_admin/policies/" + deviceType + "/" + deviceId + "/active-policy" + var serviceURLCompliance = "/devicemgt_admin/policies/" + deviceType + "/" + deviceId; + + var successCallbackCompliance = function (data) { + var viewModel = {}; + viewModel.policy = activePolicy; + viewModel.deviceType = deviceType; + if (data != null && data.complianceFeatures != null && data.complianceFeatures != undefined && data.complianceFeatures.length > 0) { + viewModel.compliance = "NON-COMPLIANT"; + viewModel.complianceFeatures = data.complianceFeatures; + var content = template(viewModel); + $("#policy-list-container").html(content); + } else { + viewModel.compliance = "COMPLIANT"; + var content = template(viewModel); + $("#policy-list-container").html(content); + $("#policy-compliance-table").addClass("hidden"); + } + + }; + + var successCallbackPolicy = function (data) { + data = JSON.parse(data); + $('#policy-spinner').addClass('hidden'); + if (data != null && data.active == true) { + activePolicy = data; + invokerUtil.get(serviceURLCompliance, + successCallbackCompliance, function (message) { + console.log(message); + }); + } + }; + + invokerUtil.get(serviceURLPolicy, + successCallbackPolicy, function (message) { + console.log(message); + }); + }); + + } + +}()); diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/load-map.js b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/load-map.js new file mode 100644 index 000000000..a2a322f8c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.device-view/public/js/load-map.js @@ -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. + */ + +$(document).ready(function () { + if (document.getElementById('device-location')) { + loadMap(); + } +}); + +function loadMap() { + var map; + + function initialize() { + var mapOptions = { + zoom: 18 + }; + var lat = $("#device-location").data("lat"); + var long = $("#device-location").data("long"); + + if (lat != null && lat != undefined && lat != "" && long != null && long != undefined && long != "") { + $("#map-error").hide(); + $("#device-location").show(); + map = new google.maps.Map(document.getElementById('device-location'), + mapOptions); + + var pos = new google.maps.LatLng(lat, long); + var marker = new google.maps.Marker({ + position: pos, + map: map + }); + + map.setCenter(pos); + } else { + $("#device-location").hide(); + $("#map-error").show(); + } + + } + + google.maps.event.addDomListener(window, 'load', initialize); +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.hbs b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.hbs new file mode 100644 index 000000000..c4bb415a1 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.hbs @@ -0,0 +1 @@ +{{unit "mdm.unit.policy.edit"}} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.json b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-edit/policy-edit.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.hbs b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.hbs new file mode 100644 index 000000000..12cffe6bd --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.hbs @@ -0,0 +1 @@ +{{unit "mdm.unit.policy.view"}} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.json b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-view/policy-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.hbs b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.hbs new file mode 100644 index 000000000..0669d1ca6 --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.hbs @@ -0,0 +1 @@ +{{unit "mdm.unit.policy.wizard"}} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.json b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.policy-wizard/policy-wizard.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/public/images/thumb.png b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/public/images/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..f4541a6ec74ebe7801d9417ee7fcf22fa27a33bc GIT binary patch literal 5195 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 z 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 +

        Windows Mobile

        +
        + +
        + +
        + +
        + +
        + +
        + +

        What it Does

        +
        +

        Connect and manage your Windows device with WSO2 IoT Server.

        +
        + +

        What You Need

        +
        +
          +
        • STEP 01   Windows + Mobile. +
        • +
        • STEP 02   Go ahead + and click [Enroll Device]. +
        • +
        • STEP 03   Proceed + to [Prepare] section. +
        • +
        +
        + + + Enroll Device + +

        +
        + +
        +

        Prepare

        +
        +
          +
        • 01 Scan QR code.
        • +
        • 02 Follow instructions in wizard. +
        • +
        • 03 Configure your workspace + account +
        • +
        +
        + +
        + +
        +

        Click on the image to zoom

        +
        + + + +
        +
        + +
        + + + +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "bottomJs"}} + +{{/zone}} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.js b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.js new file mode 100644 index 000000000..ad4f0ec9c --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.js @@ -0,0 +1,24 @@ +/* + * 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 viewModel = {}; + var devicemgtProps = require('/app/conf/devicemgt-props.js').config(); + viewModel.hostName = devicemgtProps["httpsURL"]; + return viewModel; +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.json b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.json new file mode 100644 index 000000000..9eecd8f5b --- /dev/null +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows.ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.windows.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java index 36d3bb963..366fda747 100644 --- a/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java +++ b/components/mobile-plugins/windows-plugin/org.wso2.carbon.device.mgt.mobile.windows/src/main/java/org/wso2/carbon/device/mgt/mobile/windows/impl/WindowsDeviceManagementService.java @@ -1,17 +1,17 @@ /* - * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * 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 + * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ @@ -36,23 +36,12 @@ public class WindowsDeviceManagementService implements DeviceManagementService { private DeviceManager deviceManager; public static final String DEVICE_TYPE_WINDOWS = "windows"; - public static final String DEVICE_TYPE_TENANT = "carbon.super"; @Override public String getType() { return WindowsDeviceManagementService.DEVICE_TYPE_WINDOWS; } - @Override - public String getProviderTenantDomain() { - return DEVICE_TYPE_TENANT; - } - - @Override - public boolean isSharedWithAllTenants() { - return true; - } - @Override public void init() throws DeviceManagementException { this.deviceManager = new WindowsDeviceManager(); diff --git a/components/mobile-plugins/windows-plugin/pom.xml b/components/mobile-plugins/windows-plugin/pom.xml index e5de76e61..17507c4ca 100644 --- a/components/mobile-plugins/windows-plugin/pom.xml +++ b/components/mobile-plugins/windows-plugin/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -27,7 +27,6 @@ 4.0.0 - org.wso2.carbon.devicemgt-plugins windows-plugin pom WSO2 Carbon - Mobile Plugins @@ -35,7 +34,8 @@ org.wso2.carbon.device.mgt.mobile.windows - org.wso2.carbon.device.mgt.mobile.windows.agent + org.wso2.carbon.device.mgt.mobile.windows.api + org.wso2.carbon.device.mgt.mobile.windows.ui diff --git a/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml new file mode 100644 index 000000000..7d94f16e3 --- /dev/null +++ b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml @@ -0,0 +1,192 @@ + + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-base-plugin-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.iot.feature + pom + 2.1.0-SNAPSHOT + WSO2 Carbon - IoT Device Management Feature + http://wso2.org + This feature contains the core bundles required for IoT Server + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.api + war + + + org.json.wso2 + json + + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + net.sf.ehcache.wso2 + ehcache + 1.5.0.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.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.ui + + ${project.version} + zip + true + + ${project.build.directory}/maven-shared-archive-resources/jaggeryapps/devicemgt + + **/* + + + + + + copy + package + + copy + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot.api + war + true + ${project.build.directory}/maven-shared-archive-resources/webapps/ + common.war + + + + + + + + org.wso2.maven + carbon-p2-plugin + ${carbon.p2.plugin.version} + + + p2-feature-generation + package + + p2-feature-gen + + + org.wso2.carbon.device.mgt.iot + ../../../features/etc/feature.properties + + + org.wso2.carbon.p2.category.type:server + org.eclipse.equinox.p2.type.group:false + + + + + org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.iot:${carbon.devicemgt.plugins.version} + + + org.json.wso2:json:${commons-json.version} + + + org.eclipse.paho:org.eclipse.paho.client.mqttv3:${eclipse.paho.version} + + + org.igniterealtime.smack.wso2:smack:${smack.wso2.version} + + + org.igniterealtime.smack.wso2:smackx:${smackx.wso2.version} + + + + org.wso2.carbon.core.server:${carbon.kernel.version} + + org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version} + + + + + + + + + diff --git a/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties new file mode 100644 index 000000000..33bb0980d --- /dev/null +++ b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +custom = true diff --git a/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xml b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xml new file mode 100644 index 000000000..b245214be --- /dev/null +++ b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xml @@ -0,0 +1,45 @@ + + + + + + + MQTT + true + org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttControlPublisher + MQTT + + tcp://localhost + 1883 + admin + admin + + + + XMPP + false + org.wso2.carbon.device.mgt.iot.controlqueue.xmpp.XmppServerClient + XMPP + http://204.232.188.215 + 9090 + admin + wso2iot123 + + + diff --git a/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xsd b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xsd new file mode 100644 index 000000000..99b00269e --- /dev/null +++ b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicemgt-config.xsd @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf new file mode 100644 index 000000000..77c750196 --- /dev/null +++ b/features/iot-plugins-feature/iot-base-plugin-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf @@ -0,0 +1,8 @@ +instructions.configure = \ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,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.wso2.carbon.device.mgt.iot_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../conf/iot/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/conf/devicemgt-config.xml,target:${installFolder}/../../conf/iot/devicemgt-config.xml,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot_${feature.version}/conf/devicemgt-config.xsd,target:${installFolder}/../../conf/iot/devicemgt-config.xsd,overwrite:true);\ \ No newline at end of file diff --git a/features/iot-plugins-feature/iot-base-plugin-feature/pom.xml b/features/iot-plugins-feature/iot-base-plugin-feature/pom.xml new file mode 100644 index 000000000..040202a90 --- /dev/null +++ b/features/iot-plugins-feature/iot-base-plugin-feature/pom.xml @@ -0,0 +1,40 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + iot-plugins-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + iot-base-plugin-feature + 2.1.0-SNAPSHOT + pom + WSO2 Carbon - Device Management IoT Base Plugin Feature + http://wso2.org + + + org.wso2.carbon.device.mgt.iot.feature + + + diff --git a/features/iot-plugins-feature/pom.xml b/features/iot-plugins-feature/pom.xml new file mode 100644 index 000000000..c1ebe4604 --- /dev/null +++ b/features/iot-plugins-feature/pom.xml @@ -0,0 +1,40 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + carbon-device-mgt-plugins-parent + 2.1.0-SNAPSHOT + ../../pom.xml + + + 4.0.0 + iot-plugins-feature + 2.1.0-SNAPSHOT + pom + WSO2 Carbon - Device Management IoT Plugins Feature + http://wso2.org + + + iot-base-plugin-feature + + + diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/pom.xml b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/pom.xml new file mode 100644 index 000000000..364d32830 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/pom.xml @@ -0,0 +1,213 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + android-plugin-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.android.feature + pom + 2.1.0-SNAPSHOT + WSO2 Carbon - Android Device Management Feature + http://wso2.org + This feature contains the core bundles required for Android Device Management + functionality + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.android + + + com.h2database.wso2 + h2-database-engine + + + + + + + maven-resources-plugin + 2.6 + + + 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.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.android.ui + + ${project.version} + zip + true + + ${project.build.directory}/maven-shared-archive-resources/jaggeryapps/devicemgt + + **/* + + + + + + copy-jaxrs-war + package + + copy + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.android.api + + war + true + ${project.build.directory}/maven-shared-archive-resources/webapps/ + + mdm-android-agent.war + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + + create-android-mobile-plugin-mgt-schema + package + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + org.wso2.maven + carbon-p2-plugin + ${carbon.p2.plugin.version} + + + p2-feature-generation + package + + p2-feature-gen + + + org.wso2.carbon.device.mgt.mobile.android + ../../../../features/etc/feature.properties + + + + org.wso2.carbon.p2.category.type:server + + org.eclipse.equinox.p2.type.group:false + + + + + + org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.mobile.android:${carbon.mobile.device.mgt.version} + + + + + org.wso2.carbon.core.server:${carbon.kernel.version} + + + org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version} + + + + + + + + + + diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/build.properties b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/build.properties new file mode 100644 index 000000000..33bb0980d --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/build.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +custom = true diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/conf/mobile-config.xml b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/conf/mobile-config.xml new file mode 100644 index 000000000..39abe6e01 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/conf/mobile-config.xml @@ -0,0 +1,71 @@ + + + + + + + + + jdbc/MobileAndroidDM_DS + + + + + jdbc/MobileWindowsDM_DS + + + + + + + + appmanager + admin + /devices + 1.0.0 + http://localhost:9763/test/app + http,https + + + enrol + admin + /enroll + 1.0.0 + http://localhost:9763/mdm-android-agent/enrollment + http,https + + + license + admin + /license + 1.0.0 + http://localhost:9763/mdm-android-agent/devices/license + http,https + + + operation + admin + /operation + 1.0.0 + http://localhost:9763/mdm-android-agent/operations + http,https + + + + diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/configs/android.json b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/configs/android.json new file mode 100644 index 000000000..3601ecb51 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/configs/android.json @@ -0,0 +1,6 @@ +{ + "deviceType": { + "label": "Android", + "category" : "mobile" + } +} diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/h2.sql b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/h2.sql new file mode 100644 index 000000000..3673fd122 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/h2.sql @@ -0,0 +1,30 @@ + +-- ----------------------------------------------------- +-- Table `AD_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_DEVICE` ( + `DEVICE_ID` VARCHAR(45) NOT NULL, + `GCM_TOKEN` VARCHAR(1000) NULL DEFAULT NULL, + `DEVICE_INFO` VARCHAR(8000) NULL DEFAULT NULL, + `IMEI` VARCHAR(45) NULL DEFAULT NULL, + `IMSI` VARCHAR(45) NULL DEFAULT NULL, + `OS_VERSION` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_MODEL` VARCHAR(45) NULL DEFAULT NULL, + `VENDOR` VARCHAR(45) NULL DEFAULT NULL, + `LATITUDE` VARCHAR(45) NULL DEFAULT NULL, + `LONGITUDE` VARCHAR(45) NULL DEFAULT NULL, + `SERIAL` VARCHAR(45) NULL DEFAULT NULL, + `MAC_ADDRESS` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (`DEVICE_ID`)); + +-- ----------------------------------------------------- +-- Table `AD_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_FEATURE` ( + `ID` INT NOT NULL AUTO_INCREMENT, + `CODE` VARCHAR(45) NOT NULL, + `NAME` VARCHAR(100) NULL, + `DESCRIPTION` VARCHAR(200) NULL, + PRIMARY KEY (`ID`)); + diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mssql.sql b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mssql.sql new file mode 100644 index 000000000..be8caf6c4 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mssql.sql @@ -0,0 +1,29 @@ +-- ----------------------------------------------------- +-- Table `AD_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE AD_DEVICE ( + DEVICE_ID VARCHAR(45) NOT NULL, + GCM_TOKEN VARCHAR(1000) NULL DEFAULT NULL, + DEVICE_INFO VARCHAR(8000) NULL DEFAULT NULL, + IMEI VARCHAR(45) NULL DEFAULT NULL, + IMSI VARCHAR(45) NULL DEFAULT NULL, + OS_VERSION VARCHAR(45) NULL DEFAULT NULL, + DEVICE_MODEL VARCHAR(45) NULL DEFAULT NULL, + VENDOR VARCHAR(45) NULL DEFAULT NULL, + LATITUDE VARCHAR(45) NULL DEFAULT NULL, + LONGITUDE VARCHAR(45) NULL DEFAULT NULL, + SERIAL VARCHAR(45) NULL DEFAULT NULL, + MAC_ADDRESS VARCHAR(45) NULL DEFAULT NULL, + DEVICE_NAME VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (DEVICE_ID)); + +-- ----------------------------------------------------- +-- Table `AD_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE AD_FEATURE ( + ID INT NOT NULL IDENTITY, + CODE VARCHAR(45) NOT NULL, + NAME VARCHAR(100) NULL, + DESCRIPTION VARCHAR(200) NULL, + PRIMARY KEY (ID) +); diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mysql.sql b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mysql.sql new file mode 100644 index 000000000..8e85b92c2 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/mysql.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Table `AD_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_DEVICE` ( + `DEVICE_ID` VARCHAR(45) NOT NULL, + `GCM_TOKEN` VARCHAR(1000) NULL DEFAULT NULL, + `DEVICE_INFO` VARCHAR(8000) NULL DEFAULT NULL, + `IMEI` VARCHAR(45) NULL DEFAULT NULL, + `IMSI` VARCHAR(45) NULL DEFAULT NULL, + `OS_VERSION` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_MODEL` VARCHAR(45) NULL DEFAULT NULL, + `VENDOR` VARCHAR(45) NULL DEFAULT NULL, + `LATITUDE` VARCHAR(45) NULL DEFAULT NULL, + `LONGITUDE` VARCHAR(45) NULL DEFAULT NULL, + `SERIAL` VARCHAR(45) NULL DEFAULT NULL, + `MAC_ADDRESS` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (`DEVICE_ID`)) + ENGINE = InnoDB; + +-- ----------------------------------------------------- +-- Table `AD_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AD_FEATURE` ( + `ID` INT NOT NULL AUTO_INCREMENT, + `CODE` VARCHAR(45) NOT NULL, + `NAME` VARCHAR(100) NULL, + `DESCRIPTION` VARCHAR(200) NULL, + PRIMARY KEY (`ID`) + ) ENGINE = InnoDB; + diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/oracle.sql b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/oracle.sql new file mode 100644 index 000000000..1331581e7 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/oracle.sql @@ -0,0 +1,50 @@ +-- ----------------------------------------------------- +-- Table `AD_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE AD_DEVICE ( + DEVICE_ID VARCHAR(45) NOT NULL , + DEVICE_INFO VARCHAR(4000) DEFAULT NULL, + GCM_TOKEN VARCHAR(1000) DEFAULT NULL, + IMEI VARCHAR(45) DEFAULT NULL, + IMSI VARCHAR(45) DEFAULT NULL, + OS_VERSION VARCHAR(45) DEFAULT NULL, + DEVICE_MODEL VARCHAR(45) DEFAULT NULL, + VENDOR VARCHAR(45) DEFAULT NULL, + LATITUDE VARCHAR(45) DEFAULT NULL, + LONGITUDE VARCHAR(45) DEFAULT NULL, + SERIAL VARCHAR(45) DEFAULT NULL, + MAC_ADDRESS VARCHAR(45) DEFAULT NULL, + DEVICE_NAME VARCHAR(100) DEFAULT NULL, + CONSTRAINT PK_AD_DEVICE PRIMARY KEY (DEVICE_ID) +) +/ + +-- ----------------------------------------------------- +-- Table `AD_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE AD_FEATURE ( + ID INT NOT NULL, + CODE VARCHAR(45) NOT NULL, + NAME VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(200) DEFAULT NULL, + CONSTRAINT AD_FEATURE PRIMARY KEY (ID) +) +/ + +-- ----------------------------------------------------- +-- Sequence `AD_FEATURE_ID_INC_SEQ` +-- ----------------------------------------------------- +CREATE SEQUENCE AD_FEATURE_ID_INC_SEQ START WITH 1 INCREMENT BY 1 NOCACHE +/ +-- ----------------------------------------------------- +-- Trigger `AD_FEATURE_ID_INC_TRIG` +-- ----------------------------------------------------- +CREATE OR REPLACE TRIGGER AD_FEATURE_ID_INC_TRIG +BEFORE INSERT +ON AD_FEATURE +REFERENCING NEW AS NEW +FOR EACH ROW + BEGIN + SELECT AD_FEATURE_ID_INC_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; + END; +/ \ No newline at end of file diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/postgresql.sql b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/postgresql.sql new file mode 100644 index 000000000..e4512c53f --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/dbscripts/plugins/postgresql.sql @@ -0,0 +1,29 @@ +-- ----------------------------------------------------- +-- Table AD_DEVICE +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS AD_DEVICE ( + DEVICE_ID VARCHAR(45) NOT NULL , + DEVICE_INFO TEXT NULL DEFAULT NULL, + GCM_TOKEN VARCHAR(1000) NULL DEFAULT NULL, + IMEI VARCHAR(45) NULL DEFAULT NULL, + IMSI VARCHAR(45) NULL DEFAULT NULL, + OS_VERSION VARCHAR(45) NULL DEFAULT NULL, + DEVICE_MODEL VARCHAR(45) NULL DEFAULT NULL, + VENDOR VARCHAR(45) NULL DEFAULT NULL, + LATITUDE VARCHAR(45) NULL DEFAULT NULL, + LONGITUDE VARCHAR(45) NULL DEFAULT NULL, + SERIAL VARCHAR(45) NULL DEFAULT NULL, + MAC_ADDRESS VARCHAR(45) NULL DEFAULT NULL, + DEVICE_NAME VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (DEVICE_ID) + ); + +-- ----------------------------------------------------- +-- Table AD_FEATURE +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS AD_FEATURE ( + ID BIGSERIAL NOT NULL PRIMARY KEY, + CODE VARCHAR(45) NOT NULL, + NAME VARCHAR(100) NULL, + DESCRIPTION VARCHAR(200) NULL +); diff --git a/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/p2.inf b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/p2.inf new file mode 100644 index 000000000..e22961638 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/org.wso2.carbon.device.mgt.mobile.android.feature/src/main/resources/p2.inf @@ -0,0 +1,10 @@ +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.wso2.carbon.device.mgt.mobile.android_${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.wso2.carbon.device.mgt.mobile.android_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.android_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.android_${feature.version}/conf/mobile-config.xml,target:${installFolder}/../../conf/mobile-config.xml,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.android_${feature.version}/dbscripts/plugins/,target:${installFolder}/../../../dbscripts/cdm/plugins/android,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.android_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\ diff --git a/features/mobile-plugins-feature/android-plugin-feature/pom.xml b/features/mobile-plugins-feature/android-plugin-feature/pom.xml new file mode 100644 index 000000000..ec8d6fab3 --- /dev/null +++ b/features/mobile-plugins-feature/android-plugin-feature/pom.xml @@ -0,0 +1,40 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + mobile-plugins-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + android-plugin-feature + 2.1.0-SNAPSHOT + pom + WSO2 Carbon - Device Management Android Plugin Feature + http://wso2.org + + + org.wso2.carbon.device.mgt.mobile.android.feature + + + diff --git a/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml index 26b491a65..04a5dff15 100644 --- a/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml +++ b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -91,6 +91,55 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + package + + unpack + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.ui + + ${project.version} + zip + true + + ${project.build.directory}/maven-shared-archive-resources/jaggeryapps/devicemgt + + **/* + + + + + + copy + package + + copy + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.api + war + true + ${project.build.directory}/maven-shared-archive-resources/webapps/ + + mdm-admin.war + + + + + + org.wso2.maven carbon-p2-plugin diff --git a/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf index 0dab9e7d2..3beddd74a 100644 --- a/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf +++ b/features/mobile-plugins-feature/mobile-base-plugin-feature/org.wso2.carbon.device.mgt.mobile.feature/src/main/resources/p2.inf @@ -1,3 +1,7 @@ instructions.configure = \ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile_${feature.version}/conf/mobile-config.xml,target:${installFolder}/../../conf/mobile-config.xml,overwrite:true);\ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile_${feature.version}/dbscripts/plugins/,target:${installFolder}/../../../dbscripts/cdm/plugins,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.wso2.carbon.device.mgt.mobile_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\ diff --git a/features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml b/features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml index 8b0d196e5..d259b41c9 100644 --- a/features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml +++ b/features/mobile-plugins-feature/mobile-base-plugin-feature/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -30,7 +30,7 @@ mobile-base-plugin-feature 2.1.0-SNAPSHOT pom - WSO2 Carbon - Device Management Feature + WSO2 Carbon - Device Management EMM Base Plugin Feature http://wso2.org diff --git a/features/mobile-plugins-feature/pom.xml b/features/mobile-plugins-feature/pom.xml index 852a9f91e..4a8b51c32 100644 --- a/features/mobile-plugins-feature/pom.xml +++ b/features/mobile-plugins-feature/pom.xml @@ -1,21 +1,21 @@ + ~ 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. + --> @@ -30,11 +30,13 @@ mobile-plugins-feature 2.1.0-SNAPSHOT pom - WSO2 Carbon - Device Management Feature + WSO2 Carbon - Device Management EMM Plugins Feature http://wso2.org mobile-base-plugin-feature + android-plugin-feature + windows-plugin-feature diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/pom.xml b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/pom.xml new file mode 100644 index 000000000..27feffe58 --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/pom.xml @@ -0,0 +1,213 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + windows-plugin-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + org.wso2.carbon.device.mgt.mobile.windows.feature + pom + 2.1.0-SNAPSHOT + WSO2 Carbon - Windows Device Management Feature + http://wso2.org + This feature contains the core bundles required for Windows Device Management + functionality + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.windows + + + com.h2database.wso2 + h2-database-engine + + + + + + + maven-resources-plugin + 2.6 + + + 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.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.windows.ui + + ${project.version} + zip + true + + ${project.build.directory}/maven-shared-archive-resources/jaggeryapps/devicemgt + + **/* + + + + + + copy-jaxrs-war + package + + copy + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.windows.api + + war + true + ${project.build.directory}/maven-shared-archive-resources/webapps/ + + mdm-windows-agent.war + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + + create-windows-mobile-plugin-mgt-schema + package + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + org.wso2.maven + carbon-p2-plugin + ${carbon.p2.plugin.version} + + + p2-feature-generation + package + + p2-feature-gen + + + org.wso2.carbon.device.mgt.mobile.windows + ../../../../features/etc/feature.properties + + + + org.wso2.carbon.p2.category.type:server + + org.eclipse.equinox.p2.type.group:false + + + + + + org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.mobile.windows:${carbon.mobile.device.mgt.version} + + + + + org.wso2.carbon.core.server:${carbon.kernel.version} + + + org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version} + + + + + + + + + + diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/build.properties b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/build.properties new file mode 100644 index 000000000..33bb0980d --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/build.properties @@ -0,0 +1,19 @@ +# +# 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. +# + +custom = true diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/configs/windows.json b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/configs/windows.json new file mode 100644 index 000000000..33823e665 --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/configs/windows.json @@ -0,0 +1,6 @@ +{ + "deviceType": { + "label": "Windows", + "category" : "mobile" + } +} diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/h2.sql b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/h2.sql new file mode 100644 index 000000000..f1749a8a8 --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/h2.sql @@ -0,0 +1,30 @@ +-- ----------------------------------------------------- +-- Table `WIN_DEVICE` +-- ----------------------------------------------------- + CREATE TABLE IF NOT EXISTS `WIN_DEVICE` ( + `DEVICE_ID` VARCHAR(45) NOT NULL, + `CHANNEL_URI` VARCHAR(100) NULL DEFAULT NULL, + `DEVICE_INFO` TEXT NULL DEFAULT NULL, + `IMEI` VARCHAR(45) NULL DEFAULT NULL, + `IMSI` VARCHAR(45) NULL DEFAULT NULL, + `OS_VERSION` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_MODEL` VARCHAR(45) NULL DEFAULT NULL, + `VENDOR` VARCHAR(45) NULL DEFAULT NULL, + `LATITUDE` VARCHAR(45) NULL DEFAULT NULL, + `LONGITUDE` VARCHAR(45) NULL DEFAULT NULL, + `SERIAL` VARCHAR(45) NULL DEFAULT NULL, + `MAC_ADDRESS` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (`DEVICE_ID`) +); + +-- ----------------------------------------------------- +-- Table `WIN_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `WIN_FEATURE` ( + `ID` INT NOT NULL AUTO_INCREMENT, + `CODE` VARCHAR(45) NOT NULL, + `NAME` VARCHAR(100) NULL, + `DESCRIPTION` VARCHAR(200) NULL, + PRIMARY KEY (`ID`) +); diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mssql.sql b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mssql.sql new file mode 100644 index 000000000..593515185 --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mssql.sql @@ -0,0 +1,30 @@ +-- ----------------------------------------------------- +-- Table `WINDOWS_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE WIN_FEATURE ( + ID INT NOT NULL IDENTITY, + CODE VARCHAR(45) NOT NULL, + NAME VARCHAR(100) NULL, + DESCRIPTION VARCHAR(200) NULL, + PRIMARY KEY (ID) +); + +-- ----------------------------------------------------- +-- Table `WINDOWS_DEVICE` +-- ----------------------------------------------------- + CREATE TABLE WIN_DEVICE ( + DEVICE_ID VARCHAR(45) NOT NULL, + CHANNEL_URI VARCHAR(100) NULL DEFAULT NULL, + DEVICE_INFO TEXT NULL DEFAULT NULL, + IMEI VARCHAR(45) NULL DEFAULT NULL, + IMSI VARCHAR(45) NULL DEFAULT NULL, + OS_VERSION VARCHAR(45) NULL DEFAULT NULL, + DEVICE_MODEL VARCHAR(45) NULL DEFAULT NULL, + VENDOR VARCHAR(45) NULL DEFAULT NULL, + LATITUDE VARCHAR(45) NULL DEFAULT NULL, + LONGITUDE VARCHAR(45) NULL DEFAULT NULL, + SERIAL VARCHAR(45) NULL DEFAULT NULL, + MAC_ADDRESS VARCHAR(45) NULL DEFAULT NULL, + DEVICE_NAME VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (DEVICE_ID) +); diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mysql.sql b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mysql.sql new file mode 100644 index 000000000..2ebcc80f7 --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/mysql.sql @@ -0,0 +1,34 @@ +-- ----------------------------------------------------- +-- Table `WIN_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `WIN_DEVICE` ( + `DEVICE_ID` VARCHAR(45) NOT NULL, + `CHANNEL_URI` VARCHAR(100) NULL DEFAULT NULL, + `DEVICE_INFO` TEXT NULL DEFAULT NULL, + `IMEI` VARCHAR(45) NULL DEFAULT NULL, + `IMSI` VARCHAR(45) NULL DEFAULT NULL, + `OS_VERSION` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_MODEL` VARCHAR(45) NULL DEFAULT NULL, + `VENDOR` VARCHAR(45) NULL DEFAULT NULL, + `LATITUDE` VARCHAR(45) NULL DEFAULT NULL, + `LONGITUDE` VARCHAR(45) NULL DEFAULT NULL, + `SERIAL` VARCHAR(45) NULL DEFAULT NULL, + `MAC_ADDRESS` VARCHAR(45) NULL DEFAULT NULL, + `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (`DEVICE_ID`)) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `WIN_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `WIN_FEATURE` ( + `ID` INT NOT NULL AUTO_INCREMENT, + `CODE` VARCHAR(45) NULL, + `NAME` VARCHAR(100) NULL, + `DESCRIPTION` VARCHAR(200) NULL, + PRIMARY KEY (`ID`)) +ENGINE = InnoDB; + + + diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/oracle.sql b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/oracle.sql new file mode 100644 index 000000000..a7a389264 --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/oracle.sql @@ -0,0 +1,51 @@ +-- ----------------------------------------------------- +-- Table `WIN_DEVICE` +-- ----------------------------------------------------- +CREATE TABLE WIN_DEVICE ( + DEVICE_ID VARCHAR(45) NOT NULL, + CHANNEL_URI VARCHAR(100) DEFAULT NULL, + DEVICE_INFO VARCHAR2(4000) DEFAULT NULL, + IMEI VARCHAR(45) DEFAULT NULL, + IMSI VARCHAR(45) DEFAULT NULL, + OS_VERSION VARCHAR(45) DEFAULT NULL, + DEVICE_MODEL VARCHAR(45) DEFAULT NULL, + VENDOR VARCHAR(45) DEFAULT NULL, + LATITUDE VARCHAR(45) DEFAULT NULL, + LONGITUDE VARCHAR(45) DEFAULT NULL, + SERIAL VARCHAR(45) DEFAULT NULL, + MAC_ADDRESS VARCHAR(45) DEFAULT NULL, + DEVICE_NAME VARCHAR(100) DEFAULT NULL, + CONSTRAINT PK_WIN_DEVICE PRIMARY KEY (DEVICE_ID) +) +/ + +-- ----------------------------------------------------- +-- Table `WIN_FEATURE` +-- ----------------------------------------------------- +CREATE TABLE WIN_FEATURE ( + ID INT NOT NULL, + CODE VARCHAR(45) NOT NULL, + NAME VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(200) NULL, + PRIMARY KEY (ID) +) +/ + +-- ----------------------------------------------------- +-- Sequence `WIN_FEATURE_ID_INC_SEQ` +-- ----------------------------------------------------- +CREATE SEQUENCE WIN_FEATURE_ID_INC_SEQ START WITH 1 INCREMENT BY 1 NOCACHE +/ + +-- ----------------------------------------------------- +-- Trigger `WIN_FEATURE_ID_INC_TRIG` +-- ----------------------------------------------------- +CREATE OR REPLACE TRIGGER WIN_FEATURE_ID_INC_TRIG +BEFORE INSERT +ON WIN_FEATURE +REFERENCING NEW AS NEW +FOR EACH ROW + BEGIN + SELECT WIN_FEATURE_ID_INC_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; + END; +/ \ No newline at end of file diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/postgresql.sql b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/postgresql.sql new file mode 100644 index 000000000..d7444757d --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/dbscripts/plugins/postgresql.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Table WIN_DEVICE +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS WIN_DEVICE ( + DEVICE_ID VARCHAR(45) NOT NULL, + CHANNEL_URI VARCHAR(100) NULL DEFAULT NULL, + DEVICE_INFO TEXT NULL DEFAULT NULL, + IMEI VARCHAR(45) NULL DEFAULT NULL, + IMSI VARCHAR(45) NULL DEFAULT NULL, + OS_VERSION VARCHAR(45) NULL DEFAULT NULL, + DEVICE_MODEL VARCHAR(45) NULL DEFAULT NULL, + VENDOR VARCHAR(45) NULL DEFAULT NULL, + LATITUDE VARCHAR(45) NULL DEFAULT NULL, + LONGITUDE VARCHAR(45) NULL DEFAULT NULL, + SERIAL VARCHAR(45) NULL DEFAULT NULL, + MAC_ADDRESS VARCHAR(45) NULL DEFAULT NULL, + DEVICE_NAME VARCHAR(100) NULL DEFAULT NULL, + PRIMARY KEY (DEVICE_ID) + ); + +-- ----------------------------------------------------- +-- Table WIN_FEATURE +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS WIN_FEATURE ( + ID SERIAL NOT NULL, + CODE VARCHAR(45) NULL, + NAME VARCHAR(100) NULL, + DESCRIPTION VARCHAR(200) NULL, + PRIMARY KEY (ID) + ); + diff --git a/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/p2.inf b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/p2.inf new file mode 100644 index 000000000..09f27767d --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/org.wso2.carbon.device.mgt.mobile.windows.feature/src/main/resources/p2.inf @@ -0,0 +1,9 @@ +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.wso2.carbon.device.mgt.mobile.windows_${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.wso2.carbon.device.mgt.mobile.windows_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.windows_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.windows_${feature.version}/dbscripts/plugins/,target:${installFolder}/../../../dbscripts/cdm/plugins/windows,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.mobile.windows_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\ diff --git a/features/mobile-plugins-feature/windows-plugin-feature/pom.xml b/features/mobile-plugins-feature/windows-plugin-feature/pom.xml new file mode 100644 index 000000000..f00b2874a --- /dev/null +++ b/features/mobile-plugins-feature/windows-plugin-feature/pom.xml @@ -0,0 +1,40 @@ + + + + + + + org.wso2.carbon.devicemgt-plugins + mobile-plugins-feature + 2.1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + windows-plugin-feature + 2.1.0-SNAPSHOT + pom + WSO2 Carbon - Device Management Windows Plugin Feature + http://wso2.org + + + org.wso2.carbon.device.mgt.mobile.windows.feature + + + diff --git a/pom.xml b/pom.xml index c31949282..bcaf766c7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,22 +1,21 @@ - + ~ 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. + --> @@ -40,6 +39,7 @@ components/mobile-plugins components/iot-plugins features/mobile-plugins-feature + features/iot-plugins-feature @@ -498,6 +498,11 @@ org.wso2.carbon.device.mgt.mobile.impl ${carbon.mobile.device.mgt.version} + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.api + ${carbon.mobile.device.mgt.version} + org.wso2.carbon.devicemgt-plugins org.wso2.carbon.device.mgt.mobile.url.printer @@ -508,11 +513,30 @@ org.wso2.carbon.device.mgt.mobile ${carbon.mobile.device.mgt.version} + + org.wso2.carbon.devicemgt-plugins org.wso2.carbon.device.mgt.mobile.android ${carbon.mobile.device.mgt.version} + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.android.api + ${carbon.mobile.device.mgt.version} + + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.windows + ${carbon.mobile.device.mgt.version} + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.mobile.windows.api + ${carbon.mobile.device.mgt.version} + From 8c6690a59759117a2eaaf420f4658a4e819b1612 Mon Sep 17 00:00:00 2001 From: charithag Date: Wed, 30 Mar 2016 02:10:31 +0530 Subject: [PATCH 09/10] Update MDM admin content from product-emm --- .../org/wso2/carbon/mdm/api/Certificate.java | 25 +++--- .../wso2/carbon/mdm/api/Configuration.java | 2 +- .../carbon/mdm/api/DeviceInformation.java | 83 +++++++++++++++++++ .../org/wso2/carbon/mdm/api/DeviceSearch.java | 56 +++++++++++++ .../java/org/wso2/carbon/mdm/api/Feature.java | 7 +- .../org/wso2/carbon/mdm/api/MobileDevice.java | 4 +- .../java/org/wso2/carbon/mdm/api/Role.java | 8 +- .../wso2/carbon/mdm/api/util/MDMAPIUtils.java | 28 +++++++ .../carbon/mdm/api/util/ResponsePayload.java | 11 +-- .../src/main/webapp/META-INF/permissions.xml | 19 +++++ .../src/main/webapp/WEB-INF/cxf-servlet.xml | 24 ++++++ 11 files changed, 237 insertions(+), 30 deletions(-) create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceInformation.java create mode 100644 components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceSearch.java diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java index c637252a5..e7ba2fd3e 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Certificate.java @@ -18,6 +18,7 @@ package org.wso2.carbon.mdm.api; +import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.certificate.mgt.core.dao.CertificateManagementDAOException; @@ -29,19 +30,13 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; import org.wso2.carbon.mdm.api.common.MDMAPIException; import org.wso2.carbon.mdm.api.util.MDMAPIUtils; +import org.wso2.carbon.mdm.api.util.ResponsePayload; import org.wso2.carbon.mdm.beans.EnrollmentCertificate; +import org.wso2.carbon.mdm.exception.*; import org.wso2.carbon.mdm.exception.BadRequestException; -import org.wso2.carbon.mdm.exception.Message; +import org.wso2.carbon.mdm.util.MDMUtil; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.ArrayList; @@ -50,8 +45,7 @@ import java.util.List; /** * All the certificate related tasks such as saving certificates, can be done through this endpoint. */ -@SuppressWarnings("NonJaxWsWebServices") -@Produces({"application/json", "application/xml" }) +@Produces({ "application/json", "application/xml" }) @Consumes({ "application/json", "application/xml" }) public class Certificate { @@ -71,7 +65,8 @@ public class Certificate { EnrollmentCertificate[] enrollmentCertificates) throws MDMAPIException { MediaType responseMediaType = MDMAPIUtils.getResponseMediaType(acceptHeader); CertificateManagementService certificateService; - List certificates = new ArrayList<>(); + List certificates = new ArrayList(); org.wso2.carbon.certificate.mgt.core.bean.Certificate certificate; certificateService = MDMAPIUtils.getCertificateManagementService(); try { @@ -184,9 +179,9 @@ public class Certificate { try { deleted = certificateService.removeCertificate(serialNumber); if(deleted){ - return Response.status(Response.Status.OK).entity(true).type(responseMediaType).build(); + return Response.status(Response.Status.OK).entity(deleted).type(responseMediaType).build(); } else { - return Response.status(Response.Status.GONE).entity(false).type(responseMediaType).build(); + return Response.status(Response.Status.GONE).entity(deleted).type(responseMediaType).build(); } } catch (CertificateManagementDAOException e) { String msg = "Error occurred while converting PEM file to X509Certificate"; diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java index 6fd806f33..eb8a5e138 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Configuration.java @@ -79,7 +79,7 @@ public class Configuration { configurationEntry.setValue(PolicyManagerUtil.getMonitoringFequency()); List configList = tenantConfiguration.getConfiguration(); if (configList == null) { - configList = new ArrayList<>(); + configList = new ArrayList(); } configList.add(configurationEntry); tenantConfiguration.setConfiguration(configList); diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceInformation.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceInformation.java new file mode 100644 index 000000000..c8503d32f --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceInformation.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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; +import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceDetailsMgtException; +import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +public class DeviceInformation { + + private static Log log = LogFactory.getLog(DeviceInformation.class); + + @GET + @Path("{type}/{id}") + public Response getDeviceInfo(@PathParam("type") String type, @PathParam("id") String id) throws MDMAPIException { + DeviceInformationManager informationManager; + DeviceInfo deviceInfo; + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(id); + deviceIdentifier.setType(type); + informationManager = MDMAPIUtils.getDeviceInformationManagerService(); + deviceInfo = informationManager.getDeviceInfo(deviceIdentifier); + + } catch (DeviceDetailsMgtException e) { + String msg = "Error occurred while getting the device information."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).entity(deviceInfo).build(); + } + + + @GET + @Path("location/{type}/{id}") + public Response getDeviceLocation(@PathParam("type") String type, @PathParam("id") String id) throws MDMAPIException { + DeviceInformationManager informationManager; + DeviceLocation deviceLocation; + try { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(id); + deviceIdentifier.setType(type); + informationManager = MDMAPIUtils.getDeviceInformationManagerService(); + deviceLocation = informationManager.getDeviceLocation(deviceIdentifier); + + } catch (DeviceDetailsMgtException e) { + String msg = "Error occurred while getting the device location."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).entity(deviceLocation).build(); + } +} + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceSearch.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceSearch.java new file mode 100644 index 000000000..ab1bf5194 --- /dev/null +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/DeviceSearch.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.wso2.carbon.mdm.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.device.details.DeviceWrapper; +import org.wso2.carbon.device.mgt.common.search.SearchContext; +import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService; +import org.wso2.carbon.device.mgt.core.search.mgt.SearchMgtException; +import org.wso2.carbon.mdm.api.common.MDMAPIException; +import org.wso2.carbon.mdm.api.util.MDMAPIUtils; + +import javax.ws.rs.GET; +import javax.ws.rs.core.Response; +import java.util.List; + +public class DeviceSearch { + + private static Log log = LogFactory.getLog(DeviceSearch.class); + + @GET + public Response getDeviceInfo(SearchContext searchContext) throws MDMAPIException { + SearchManagerService searchManagerService; + List devices; + try { + searchManagerService = MDMAPIUtils.getSearchManagerService(); + devices = searchManagerService.search(searchContext); + + } catch (SearchMgtException e) { + String msg = "Error occurred while searching the device information."; + log.error(msg, e); + throw new MDMAPIException(msg, e); + } + return Response.status(HttpStatus.SC_OK).entity(devices).build(); + } +} + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java index 1cd357b94..b98baab48 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Feature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * 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 @@ -11,10 +11,11 @@ * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ + package org.wso2.carbon.mdm.api; import org.apache.commons.logging.Log; @@ -39,7 +40,7 @@ public class Feature { * Get all features for Mobile Device Type * * @return Feature - * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * @throws MDMAPIException * */ @GET diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java index be7c9bda3..f37781747 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/MobileDevice.java @@ -133,7 +133,7 @@ public class MobileDevice { * @param user User Name * @param tenantDomain tenant domain * @return Device - * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * @throws MDMAPIException */ @GET @Path("user/{user}/{tenantDomain}") @@ -184,7 +184,7 @@ public class MobileDevice { public List getDevicesByName(@PathParam("name") String deviceName, @PathParam("tenantDomain") String tenantDomain) throws MDMAPIException { - List devices; + List devices; try { devices = MDMAPIUtils.getDeviceManagementService().getDevicesByName(deviceName); } catch (DeviceManagementException e) { diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java index dda4f243f..f0157ef4e 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/Role.java @@ -49,7 +49,7 @@ public class Role { * Get user roles (except all internal roles) from system. * * @return A list of users - * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * @throws MDMAPIException */ @GET @Produces ({MediaType.APPLICATION_JSON}) @@ -85,7 +85,7 @@ public class Role { * Get user roles by user store(except all internal roles) from system. * * @return A list of users - * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * @throws MDMAPIException */ @GET @Path ("{userStore}") @@ -122,7 +122,7 @@ public class Role { * Get user roles by providing a filtering criteria(except all internal roles & system roles) from system. * * @return A list of users - * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * @throws MDMAPIException */ @GET @Path ("search") @@ -205,7 +205,7 @@ public class Role { * Get user role of the system * * @return user role - * @throws org.wso2.carbon.mdm.api.common.MDMAPIException + * @throws MDMAPIException */ @GET @Path("role") diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java index 6b7cbab59..d2a3fb9d2 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/MDMAPIUtils.java @@ -30,6 +30,8 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfigurationManagementService; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; import org.wso2.carbon.device.mgt.core.app.mgt.ApplicationManagementProviderService; +import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager; +import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.mdm.api.common.MDMAPIException; import org.wso2.carbon.ntask.core.TaskManager; @@ -282,4 +284,30 @@ public class MDMAPIUtils { return responseMediaType; } + + public static DeviceInformationManager getDeviceInformationManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceInformationManager deviceInformationManager = + (DeviceInformationManager) ctx.getOSGiService(DeviceInformationManager.class, null); + if (deviceInformationManager == null) { + String msg = "Device information Manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceInformationManager; + } + + + + public static SearchManagerService getSearchManagerService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + SearchManagerService searchManagerService = + (SearchManagerService) ctx.getOSGiService(SearchManagerService.class, null); + if (searchManagerService == null) { + String msg = "Device search manager service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return searchManagerService; + } } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java index 8cc7d3591..629400066 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/java/org/wso2/carbon/mdm/api/util/ResponsePayload.java @@ -15,6 +15,7 @@ * specific language governing permissions and limitations * under the License. */ + package org.wso2.carbon.mdm.api.util; import javax.xml.bind.annotation.XmlElement; @@ -54,21 +55,21 @@ public class ResponsePayload { this.responseContent = responseContent; } - private ResponsePayload.ResponsePayloadBuilder getBuilder() { - return new ResponsePayload.ResponsePayloadBuilder(); + private ResponsePayloadBuilder getBuilder() { + return new ResponsePayloadBuilder(); } - public static ResponsePayload.ResponsePayloadBuilder statusCode(int statusCode) { + public static ResponsePayloadBuilder statusCode(int statusCode) { ResponsePayload message = new ResponsePayload(); return message.getBuilder().statusCode(statusCode); } - public static ResponsePayload.ResponsePayloadBuilder messageFromServer(String messageFromServer) { + public static ResponsePayloadBuilder messageFromServer(String messageFromServer) { ResponsePayload message = new ResponsePayload(); return message.getBuilder().messageFromServer(messageFromServer); } - public static ResponsePayload.ResponsePayloadBuilder responseContent(String responseContent) { + public static ResponsePayloadBuilder responseContent(String responseContent) { ResponsePayload message = new ResponsePayload(); return message.getBuilder().responseContent(responseContent); } diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml index 0d5ae5347..d2442641f 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/META-INF/permissions.xml @@ -772,6 +772,25 @@ + + + + Device Information + /device-mgt/emm-admin/information/get + /information/*/* + GET + + + + Device Search + /device-mgt/emm-admin/search + /information/* + GET + + + + + diff --git a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml index 5db3ba522..e4b794b8a 100644 --- a/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/mobile-plugins/mobile-base-plugin/org.wso2.carbon.device.mgt.mobile.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -123,6 +123,26 @@
        + + + + + + + + + + + + + + + + + + + + From 5f8aeabf3ad0ad74b02828da718dbc1c417eba7f Mon Sep 17 00:00:00 2001 From: charithag Date: Wed, 30 Mar 2016 09:17:44 +0530 Subject: [PATCH 10/10] Change analytics common version to 5.0.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bcaf766c7..d250da82d 100644 --- a/pom.xml +++ b/pom.xml @@ -1134,7 +1134,7 @@ 8.1.3.v20120416 - 5.0.11-SNAPSHOT + 5.0.11 [5.0.11,6.0.0) 1.0.6-SNAPSHOT [1.0.6,2.0.0]
        + +

        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

      poS4Gt#pYO&k@o<;7p2A@W4thLg*PnqeV~p& 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 z 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

      ;IDUWW!csXi`t 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%0A}OJ)8YS)WPzR+g~$yZ4H=)zr8FiEsulTcWRUw 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%0D1Wp-ktI#HQk+N7j*7w{7zjJAbn1E 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

      + +
      + +